@deepagents/orchestrator 6.1.0 → 7.0.0
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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/arxiv/arxiv.js +153 -0
- package/dist/lib/arxiv/arxiv.js.map +7 -0
- package/dist/lib/citation.js +120 -0
- package/dist/lib/citation.js.map +7 -0
- package/dist/lib/deepplan/demo.js +518 -0
- package/dist/lib/deepplan/demo.js.map +7 -0
- package/dist/lib/deepplan/executors/generic-executor.js +196 -0
- package/dist/lib/deepplan/executors/generic-executor.js.map +7 -0
- package/dist/lib/deepplan/executors/hackernews-executor.js +210 -0
- package/dist/lib/deepplan/executors/hackernews-executor.js.map +7 -0
- package/dist/lib/deepplan/executors/product-manager-executor.js +226 -0
- package/dist/lib/deepplan/executors/product-manager-executor.js.map +7 -0
- package/dist/lib/deepplan/executors/repo-search-executor.js +76 -0
- package/dist/lib/deepplan/executors/repo-search-executor.js.map +7 -0
- package/dist/lib/deepplan/executors/research-executor.js +196 -0
- package/dist/lib/deepplan/executors/research-executor.js.map +7 -0
- package/dist/lib/deepplan/next/plan.js +1 -0
- package/dist/lib/deepplan/next/plan.js.map +7 -0
- package/dist/lib/deepplan/plan-and-solve.js +826 -0
- package/dist/lib/deepplan/plan-and-solve.js.map +7 -0
- package/dist/lib/deepplan/planner-agent.js +416 -0
- package/dist/lib/deepplan/planner-agent.js.map +7 -0
- package/dist/lib/deepplan/replanner-agent.js +418 -0
- package/dist/lib/deepplan/replanner-agent.js.map +7 -0
- package/dist/lib/deepplan/synthesizer.js +75 -0
- package/dist/lib/deepplan/synthesizer.js.map +7 -0
- package/dist/lib/deepresearch.v0.js +297 -0
- package/dist/lib/deepresearch.v0.js.map +7 -0
- package/dist/lib/deepresearch.v1.js +260 -0
- package/dist/lib/deepresearch.v1.js.map +7 -0
- package/dist/lib/deepwiki/complete-wiki.js +319 -0
- package/dist/lib/deepwiki/complete-wiki.js.map +7 -0
- package/dist/lib/deepwiki/deepwiki.js +370 -0
- package/dist/lib/deepwiki/deepwiki.js.map +7 -0
- package/dist/lib/deepwiki/gitignore-agent.js +40 -0
- package/dist/lib/deepwiki/gitignore-agent.js.map +7 -0
- package/dist/lib/deepwiki/outline-agent.d.ts.map +1 -1
- package/dist/lib/deepwiki/outline-agent.js +186 -0
- package/dist/lib/deepwiki/outline-agent.js.map +7 -0
- package/dist/lib/deepwiki/wiki-writer.js +242 -0
- package/dist/lib/deepwiki/wiki-writer.js.map +7 -0
- package/dist/lib/deepwiki/writer.js +407 -0
- package/dist/lib/deepwiki/writer.js.map +7 -0
- package/dist/lib/evolving.js +204 -0
- package/dist/lib/evolving.js.map +7 -0
- package/dist/lib/graph.js +12 -0
- package/dist/lib/graph.js.map +7 -0
- package/dist/lib/openai-deepresearch/clarrify-agent.js +67 -0
- package/dist/lib/openai-deepresearch/clarrify-agent.js.map +7 -0
- package/dist/lib/openai-deepresearch/lead-research.js +168 -0
- package/dist/lib/openai-deepresearch/lead-research.js.map +7 -0
- package/dist/lib/openai-deepresearch/openai-deepresearch.js +179 -0
- package/dist/lib/openai-deepresearch/openai-deepresearch.js.map +7 -0
- package/dist/lib/openai-deepresearch/reasearcher.js +62 -0
- package/dist/lib/openai-deepresearch/reasearcher.js.map +7 -0
- package/dist/lib/openai-deepresearch/research-brief.js +59 -0
- package/dist/lib/openai-deepresearch/research-brief.js.map +7 -0
- package/dist/lib/repo-context.js +11 -0
- package/dist/lib/repo-context.js.map +7 -0
- package/package.json +8 -8
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
// packages/orchestrator/src/lib/deepresearch.v0.ts
|
|
2
|
+
import { groq } from "@ai-sdk/groq";
|
|
3
|
+
import { openai } from "@ai-sdk/openai";
|
|
4
|
+
import { uniqBy } from "lodash-es";
|
|
5
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import z from "zod";
|
|
7
|
+
import { agent, execute, generate, lmstudio } from "@deepagents/agent";
|
|
8
|
+
import { fastembed, nodeSQLite, similaritySearch } from "@deepagents/retrieval";
|
|
9
|
+
import * as connectors from "@deepagents/retrieval/connectors";
|
|
10
|
+
var searchQueryAgent = agent({
|
|
11
|
+
name: "search-query-generator",
|
|
12
|
+
model: groq("openai/gpt-oss-20b"),
|
|
13
|
+
prompt: [
|
|
14
|
+
`You are an expert research assistant. Given the user's query, generate up to four distinct, precise SEMANTIC search queries well-suited for a vector database of repository content (code, docs, comments).`,
|
|
15
|
+
`Rules: (1) Do NOT include file paths, globs, regex, repository names, or line numbers. (2) Avoid repeating the same idea; ensure diversity (architecture, data flow, services, APIs, domain terms). (3) Keep each query concise (3\u201310 words). (4) Prefer concept-level phrasing over filenames.`,
|
|
16
|
+
"Return only the queries as plain strings; no numbering or extra commentary."
|
|
17
|
+
],
|
|
18
|
+
output: z.object({ items: z.array(z.string()).max(4) })
|
|
19
|
+
});
|
|
20
|
+
var repoContextAgent = agent({
|
|
21
|
+
name: "repo-context-summarizer",
|
|
22
|
+
model: groq("openai/gpt-oss-20b"),
|
|
23
|
+
prompt: [
|
|
24
|
+
"You are an expert codebase analyst. You will receive samples from a repository (file paths with short content snippets).",
|
|
25
|
+
"Produce a concise context summary capturing: primary domains, major modules/components, key data models, important services/APIs, external integrations, and notable terminology or patterns.",
|
|
26
|
+
"Format as short markdown sections with bullet points. Keep under 400 words. Do not speculate beyond the provided snippets."
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
var newSearchQueriesAgent = agent({
|
|
30
|
+
name: "research-continuation-planner",
|
|
31
|
+
model: groq("openai/gpt-oss-120b"),
|
|
32
|
+
prompt: "You are an analytical research assistant. Based on the original query, the search queries performed so far, and the extracted contexts, determine if further research is needed.",
|
|
33
|
+
output: z.object({
|
|
34
|
+
needsMoreResearch: z.boolean().describe("Whether additional research is needed"),
|
|
35
|
+
newQueries: z.array(z.string()).max(4).describe(
|
|
36
|
+
"Up to four new search queries if more research is needed, empty array otherwise"
|
|
37
|
+
),
|
|
38
|
+
reasoning: z.string().optional().describe("Brief explanation of the decision")
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
var pageUsefulnessAgent = agent({
|
|
42
|
+
name: "page-usefulness-evaluator",
|
|
43
|
+
model: lmstudio("qwen/qwen3-4b-2507"),
|
|
44
|
+
prompt: [
|
|
45
|
+
"You are a strict and concise evaluator of research relevance.",
|
|
46
|
+
"Given the user's query and the content of a repository file, determine if the file contains information relevant and useful for addressing the query.",
|
|
47
|
+
"Respond with exactly one word: 'Yes' if the file is useful, or 'No' if it is not."
|
|
48
|
+
],
|
|
49
|
+
output: z.object({ answer: z.enum(["Yes", "No"]) })
|
|
50
|
+
});
|
|
51
|
+
var extractRelevantContextAgent = agent({
|
|
52
|
+
name: "relevant-context-extractor",
|
|
53
|
+
model: groq("openai/gpt-oss-20b"),
|
|
54
|
+
prompt: [
|
|
55
|
+
"You are an expert in extracting and summarizing relevant information.",
|
|
56
|
+
"Given the user's query, the search query that led to this page, and the file content, extract all pieces of information that are relevant to answering the user's query.",
|
|
57
|
+
"Return only the relevant context as plain text without commentary."
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
var finalReportAgent = agent({
|
|
61
|
+
name: "final-report-writer",
|
|
62
|
+
model: openai("gpt-4.1"),
|
|
63
|
+
prompt: `You are an expert product manager that is working on reversing existing product to user stories based on a developer question/inquiry. Based on the gathered contexts below and the original query, write a comprehensive, well-structured, and detailed report that addresses the query thoroughly.
|
|
64
|
+
Include all relevant insights and conclusions without extraneous commentary.`
|
|
65
|
+
});
|
|
66
|
+
async function generateSearchQueries(input, repoContext) {
|
|
67
|
+
const { output } = await generate(
|
|
68
|
+
searchQueryAgent,
|
|
69
|
+
`User Query: ${input}
|
|
70
|
+
|
|
71
|
+
Repository Context Summary:
|
|
72
|
+
${repoContext}`,
|
|
73
|
+
{}
|
|
74
|
+
);
|
|
75
|
+
const result = output;
|
|
76
|
+
return uniqBy(
|
|
77
|
+
(result.items ?? []).map((s) => s.trim()).filter(Boolean),
|
|
78
|
+
(s) => s.toLowerCase()
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
async function retrieve(query) {
|
|
82
|
+
const results = await similaritySearch(query, {
|
|
83
|
+
connector: connectors.repo(
|
|
84
|
+
"/Users/ezzabuzaid/Desktop/mo/virtual-care",
|
|
85
|
+
[".ts", ".tsx", ".md", ".prisma"],
|
|
86
|
+
"never"
|
|
87
|
+
),
|
|
88
|
+
store: nodeSQLite("deepsearch.sqlite", 384),
|
|
89
|
+
embedder: fastembed()
|
|
90
|
+
});
|
|
91
|
+
return results.map((it) => ({
|
|
92
|
+
snippet: it.content,
|
|
93
|
+
source: it.document_id,
|
|
94
|
+
similarity: it.similarity
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
async function getNewSearchQueries(userQuery, previousSearchQueries, allContexts, repoContext) {
|
|
98
|
+
const contextCombined = allContexts.join("\n\n");
|
|
99
|
+
const prompt = `User Query: ${userQuery}
|
|
100
|
+
|
|
101
|
+
Previous Search Queries: ${JSON.stringify(previousSearchQueries)}
|
|
102
|
+
|
|
103
|
+
Extracted Relevant Contexts:
|
|
104
|
+
${contextCombined}
|
|
105
|
+
|
|
106
|
+
Repository Context Summary:
|
|
107
|
+
${repoContext}
|
|
108
|
+
|
|
109
|
+
Based on the above information, determine if further research is needed. If yes, provide up to four new search queries. If the research is complete and sufficient, indicate that no more research is needed.`;
|
|
110
|
+
try {
|
|
111
|
+
const { output } = await generate(newSearchQueriesAgent, prompt, {});
|
|
112
|
+
const result = output;
|
|
113
|
+
if (!result.needsMoreResearch) {
|
|
114
|
+
console.log(
|
|
115
|
+
"Research assessment: No further research needed.",
|
|
116
|
+
result.reasoning
|
|
117
|
+
);
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
console.log(
|
|
121
|
+
`Research assessment: ${result.newQueries.length} new queries generated.`,
|
|
122
|
+
result.reasoning
|
|
123
|
+
);
|
|
124
|
+
return uniqBy(
|
|
125
|
+
result.newQueries.map((s) => s.trim()).filter(Boolean),
|
|
126
|
+
(s) => s.toLowerCase()
|
|
127
|
+
);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error("Error generating new search queries:", error);
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function generateFinalReport(userQuery, formatting, allContexts) {
|
|
134
|
+
const contextCombined = allContexts.join("\n\n");
|
|
135
|
+
const prompt = `
|
|
136
|
+
Developer Query: ${userQuery}
|
|
137
|
+
Formatting: ${formatting}
|
|
138
|
+
|
|
139
|
+
Gathered Relevant Contexts:
|
|
140
|
+
${contextCombined}`;
|
|
141
|
+
return (await execute(finalReportAgent, prompt, {})).text;
|
|
142
|
+
}
|
|
143
|
+
async function isPageUseful(userQuery, pageText) {
|
|
144
|
+
const prompt = `User Query: ${userQuery}
|
|
145
|
+
|
|
146
|
+
Repo file content
|
|
147
|
+
|
|
148
|
+
${pageText}
|
|
149
|
+
|
|
150
|
+
Decide if the page is useful.`;
|
|
151
|
+
const { output } = await generate(pageUsefulnessAgent, prompt, {});
|
|
152
|
+
const result = output;
|
|
153
|
+
return result.answer === "Yes";
|
|
154
|
+
}
|
|
155
|
+
async function extractRelevantContext(userQuery, searchQuery, pageText) {
|
|
156
|
+
const prompt = `User Query: ${userQuery}
|
|
157
|
+
Search Query: ${searchQuery}
|
|
158
|
+
|
|
159
|
+
Repo file content
|
|
160
|
+
|
|
161
|
+
${pageText}
|
|
162
|
+
|
|
163
|
+
Extract the relevant context.`;
|
|
164
|
+
return (await execute(extractRelevantContextAgent, prompt, {})).text;
|
|
165
|
+
}
|
|
166
|
+
async function processFile(filePath, userQuery, searchQuery) {
|
|
167
|
+
const content = await readFile(filePath, "utf-8");
|
|
168
|
+
const useful = await isPageUseful(userQuery, content);
|
|
169
|
+
if (useful) {
|
|
170
|
+
return {
|
|
171
|
+
source: filePath,
|
|
172
|
+
content: await extractRelevantContext(userQuery, searchQuery, content)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
async function gatherRepoContext() {
|
|
178
|
+
const seeds = [
|
|
179
|
+
"project overview",
|
|
180
|
+
"backend",
|
|
181
|
+
"framework",
|
|
182
|
+
"hono express",
|
|
183
|
+
"architecture",
|
|
184
|
+
"services",
|
|
185
|
+
"prisma",
|
|
186
|
+
"database",
|
|
187
|
+
"data model",
|
|
188
|
+
"payments",
|
|
189
|
+
"billing"
|
|
190
|
+
];
|
|
191
|
+
const results = await Promise.all(seeds.map((it) => retrieve(it)));
|
|
192
|
+
const deduped = uniqBy(results.flat(), (it) => it.source);
|
|
193
|
+
const bundle = deduped.map((r, i) => `(${i + 1}) Path: ${r.source}
|
|
194
|
+
Snippet:
|
|
195
|
+
${r.snippet}`).join("\n\n---\n\n");
|
|
196
|
+
const summary = (await execute(
|
|
197
|
+
repoContextAgent,
|
|
198
|
+
`Repository Samples (path + snippet):
|
|
199
|
+
|
|
200
|
+
${bundle}
|
|
201
|
+
|
|
202
|
+
Summarize as requested.`,
|
|
203
|
+
{}
|
|
204
|
+
)).text;
|
|
205
|
+
return summary;
|
|
206
|
+
}
|
|
207
|
+
function search() {
|
|
208
|
+
const cache = {};
|
|
209
|
+
const processedSources = /* @__PURE__ */ new Set();
|
|
210
|
+
return async (queries) => {
|
|
211
|
+
const results = [];
|
|
212
|
+
for (const query of queries) {
|
|
213
|
+
if (!cache[query]) {
|
|
214
|
+
const res = await retrieve(query);
|
|
215
|
+
cache[query] = uniqBy(res, (it) => it.source);
|
|
216
|
+
}
|
|
217
|
+
results.push(cache[query]);
|
|
218
|
+
}
|
|
219
|
+
const uniqueLinks = {};
|
|
220
|
+
for (let i = 0; i < results.length; i++) {
|
|
221
|
+
const query = queries[i];
|
|
222
|
+
for (const item of results[i]) {
|
|
223
|
+
if (!uniqueLinks[item.source] && !processedSources.has(item.source)) {
|
|
224
|
+
uniqueLinks[item.source] = query;
|
|
225
|
+
processedSources.add(item.source);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return uniqueLinks;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (import.meta.main) {
|
|
233
|
+
const userQuery = "How do we process payment?";
|
|
234
|
+
const formatting = `
|
|
235
|
+
1. use ascii markdown diagrams to illustrate. I am visual learner and I love markdown.
|
|
236
|
+
2. use "user stories" to illustrate flows. we are not looking for only text or techical explanation.
|
|
237
|
+
3. user story scenario should be divided by actors and steps.
|
|
238
|
+
4. when referencing code snippets, include file path.
|
|
239
|
+
`;
|
|
240
|
+
const iterLimit = 2;
|
|
241
|
+
const aggregatedContexts = [];
|
|
242
|
+
const allSearchQueries = [];
|
|
243
|
+
let iteration = 0;
|
|
244
|
+
const repoContext = await gatherRepoContext();
|
|
245
|
+
let searchQueriesResult = await generateSearchQueries(userQuery, repoContext);
|
|
246
|
+
const performSearch = search();
|
|
247
|
+
while (iteration < iterLimit) {
|
|
248
|
+
const iterationContexts = [];
|
|
249
|
+
allSearchQueries.push(...searchQueriesResult);
|
|
250
|
+
const searchResults = await performSearch(searchQueriesResult);
|
|
251
|
+
await Promise.all(
|
|
252
|
+
Object.entries(searchResults).map(async ([source, query]) => {
|
|
253
|
+
const context = await processFile(source, userQuery, query);
|
|
254
|
+
if (context) {
|
|
255
|
+
iterationContexts.push(
|
|
256
|
+
`Source: ${context.source}
|
|
257
|
+
|
|
258
|
+
Content: ${context.content}
|
|
259
|
+
|
|
260
|
+
`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
);
|
|
265
|
+
if (iterationContexts.length === 0) {
|
|
266
|
+
console.log("No useful contexts were found in this iteration.");
|
|
267
|
+
} else {
|
|
268
|
+
aggregatedContexts.push(...iterationContexts);
|
|
269
|
+
}
|
|
270
|
+
searchQueriesResult = await getNewSearchQueries(
|
|
271
|
+
userQuery,
|
|
272
|
+
allSearchQueries,
|
|
273
|
+
aggregatedContexts,
|
|
274
|
+
repoContext
|
|
275
|
+
);
|
|
276
|
+
if (searchQueriesResult.length === 0) {
|
|
277
|
+
console.log("No further research needed. Exiting loop.");
|
|
278
|
+
break;
|
|
279
|
+
} else {
|
|
280
|
+
allSearchQueries.push(...searchQueriesResult);
|
|
281
|
+
}
|
|
282
|
+
iteration += 1;
|
|
283
|
+
}
|
|
284
|
+
console.log("\nGenerating final report...");
|
|
285
|
+
console.log("Search queries performed:", allSearchQueries);
|
|
286
|
+
const finalReport = await generateFinalReport(
|
|
287
|
+
userQuery,
|
|
288
|
+
formatting,
|
|
289
|
+
aggregatedContexts
|
|
290
|
+
);
|
|
291
|
+
await writeFile("final_report.md", finalReport);
|
|
292
|
+
}
|
|
293
|
+
export {
|
|
294
|
+
generateFinalReport,
|
|
295
|
+
getNewSearchQueries
|
|
296
|
+
};
|
|
297
|
+
//# sourceMappingURL=deepresearch.v0.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/deepresearch.v0.ts"],
|
|
4
|
+
"sourcesContent": ["import { groq } from '@ai-sdk/groq';\nimport { openai } from '@ai-sdk/openai';\nimport { uniqBy } from 'lodash-es';\nimport { readFile, writeFile } from 'node:fs/promises';\nimport z from 'zod';\n\nimport { agent, execute, generate, lmstudio } from '@deepagents/agent';\nimport { fastembed, nodeSQLite, similaritySearch } from '@deepagents/retrieval';\nimport * as connectors from '@deepagents/retrieval/connectors';\n\nconst searchQueryAgent = agent({\n name: 'search-query-generator',\n model: groq('openai/gpt-oss-20b'),\n prompt: [\n `You are an expert research assistant. Given the user's query, generate up to four distinct, precise SEMANTIC search queries well-suited for a vector database of repository content (code, docs, comments).`,\n `Rules: (1) Do NOT include file paths, globs, regex, repository names, or line numbers. (2) Avoid repeating the same idea; ensure diversity (architecture, data flow, services, APIs, domain terms). (3) Keep each query concise (3\u201310 words). (4) Prefer concept-level phrasing over filenames.`,\n 'Return only the queries as plain strings; no numbering or extra commentary.',\n ],\n output: z.object({ items: z.array(z.string()).max(4) }),\n});\n\nconst repoContextAgent = agent({\n name: 'repo-context-summarizer',\n model: groq('openai/gpt-oss-20b'),\n prompt: [\n 'You are an expert codebase analyst. You will receive samples from a repository (file paths with short content snippets).',\n 'Produce a concise context summary capturing: primary domains, major modules/components, key data models, important services/APIs, external integrations, and notable terminology or patterns.',\n 'Format as short markdown sections with bullet points. Keep under 400 words. Do not speculate beyond the provided snippets.',\n ],\n});\n\nconst newSearchQueriesAgent = agent({\n name: 'research-continuation-planner',\n model: groq('openai/gpt-oss-120b'),\n prompt:\n 'You are an analytical research assistant. Based on the original query, the search queries performed so far, and the extracted contexts, determine if further research is needed.',\n output: z.object({\n needsMoreResearch: z\n .boolean()\n .describe('Whether additional research is needed'),\n newQueries: z\n .array(z.string())\n .max(4)\n .describe(\n 'Up to four new search queries if more research is needed, empty array otherwise',\n ),\n reasoning: z\n .string()\n .optional()\n .describe('Brief explanation of the decision'),\n }),\n});\n\nconst pageUsefulnessAgent = agent({\n name: 'page-usefulness-evaluator',\n model: lmstudio('qwen/qwen3-4b-2507'),\n prompt: [\n 'You are a strict and concise evaluator of research relevance.',\n \"Given the user's query and the content of a repository file, determine if the file contains information relevant and useful for addressing the query.\",\n \"Respond with exactly one word: 'Yes' if the file is useful, or 'No' if it is not.\",\n ],\n output: z.object({ answer: z.enum(['Yes', 'No']) }),\n});\n\nconst extractRelevantContextAgent = agent({\n name: 'relevant-context-extractor',\n model: groq('openai/gpt-oss-20b'),\n\n prompt: [\n 'You are an expert in extracting and summarizing relevant information.',\n \"Given the user's query, the search query that led to this page, and the file content, extract all pieces of information that are relevant to answering the user's query.\",\n 'Return only the relevant context as plain text without commentary.',\n ],\n});\n\nconst finalReportAgent = agent({\n name: 'final-report-writer',\n model: openai('gpt-4.1'),\n prompt: `You are an expert product manager that is working on reversing existing product to user stories based on a developer question/inquiry. Based on the gathered contexts below and the original query, write a comprehensive, well-structured, and detailed report that addresses the query thoroughly.\\nInclude all relevant insights and conclusions without extraneous commentary.`,\n});\n\nasync function generateSearchQueries(\n input: string,\n repoContext: string,\n): Promise<string[]> {\n const { output } = await generate(\n searchQueryAgent,\n `User Query: ${input}\\n\\nRepository Context Summary:\\n${repoContext}`,\n {},\n );\n const result = output as { items?: string[] };\n return uniqBy(\n (result.items ?? []).map((s: string) => s.trim()).filter(Boolean),\n (s: string) => s.toLowerCase(),\n );\n}\n\nasync function retrieve(query: string) {\n const results = await similaritySearch(query, {\n connector: connectors.repo(\n '/Users/ezzabuzaid/Desktop/mo/virtual-care',\n ['.ts', '.tsx', '.md', '.prisma'],\n 'never',\n ),\n store: nodeSQLite('deepsearch.sqlite', 384),\n embedder: fastembed(),\n });\n return results.map((it) => ({\n snippet: it.content,\n source: it.document_id,\n similarity: it.similarity,\n }));\n}\n\nexport async function getNewSearchQueries(\n userQuery: string,\n previousSearchQueries: string[],\n allContexts: string[],\n repoContext: string,\n): Promise<string[]> {\n const contextCombined = allContexts.join('\\n\\n');\n const prompt = `User Query: ${userQuery}\n\nPrevious Search Queries: ${JSON.stringify(previousSearchQueries)}\n\nExtracted Relevant Contexts:\n${contextCombined}\n\nRepository Context Summary:\n${repoContext}\n\nBased on the above information, determine if further research is needed. If yes, provide up to four new search queries. If the research is complete and sufficient, indicate that no more research is needed.`;\n\n try {\n const { output } = await generate(newSearchQueriesAgent, prompt, {});\n const result = output as {\n needsMoreResearch: boolean;\n newQueries: string[];\n reasoning?: string;\n };\n\n if (!result.needsMoreResearch) {\n console.log(\n 'Research assessment: No further research needed.',\n result.reasoning,\n );\n return [];\n }\n\n console.log(\n `Research assessment: ${result.newQueries.length} new queries generated.`,\n result.reasoning,\n );\n return uniqBy(\n result.newQueries.map((s: string) => s.trim()).filter(Boolean),\n (s: string) => s.toLowerCase(),\n );\n } catch (error) {\n console.error('Error generating new search queries:', error);\n return [];\n }\n}\n\nexport async function generateFinalReport(\n userQuery: string,\n formatting: string,\n allContexts: string[],\n): Promise<string> {\n const contextCombined = allContexts.join('\\n\\n');\n const prompt = `\nDeveloper Query: ${userQuery}\nFormatting: ${formatting}\n\nGathered Relevant Contexts:\n${contextCombined}`;\n\n return (await execute(finalReportAgent, prompt, {})).text;\n}\n\nasync function isPageUseful(userQuery: string, pageText: string) {\n const prompt = `User Query: ${userQuery}\\n\\nRepo file content\\n\\n${pageText}\\n\\nDecide if the page is useful.`;\n const { output } = await generate(pageUsefulnessAgent, prompt, {} as const);\n const result = output as { answer: 'Yes' | 'No' };\n return result.answer === 'Yes';\n}\n\nasync function extractRelevantContext(\n userQuery: string,\n searchQuery: string,\n pageText: string,\n): Promise<string> {\n const prompt = `User Query: ${userQuery}\\nSearch Query: ${searchQuery}\\n\\nRepo file content\\n\\n${pageText}\\n\\nExtract the relevant context.`;\n return (await execute(extractRelevantContextAgent, prompt, {} as const)).text;\n}\n\nasync function processFile(\n filePath: string,\n userQuery: string,\n searchQuery: string,\n): Promise<{ source: string; content: string } | null> {\n const content = await readFile(filePath, 'utf-8');\n const useful = await isPageUseful(userQuery, content);\n if (useful) {\n return {\n source: filePath,\n content: await extractRelevantContext(userQuery, searchQuery, content),\n };\n }\n return null;\n}\n\nasync function gatherRepoContext(): Promise<string> {\n const seeds = [\n 'project overview',\n 'backend',\n 'framework',\n 'hono express',\n 'architecture',\n 'services',\n 'prisma',\n 'database',\n 'data model',\n 'payments',\n 'billing',\n ];\n const results = await Promise.all(seeds.map((it) => retrieve(it)));\n const deduped = uniqBy(results.flat(), (it) => it.source);\n const bundle = deduped\n .map((r, i) => `(${i + 1}) Path: ${r.source}\\nSnippet:\\n${r.snippet}`)\n .join('\\n\\n---\\n\\n');\n\n const summary = (\n await execute(\n repoContextAgent,\n `Repository Samples (path + snippet):\\n\\n${bundle}\\n\\nSummarize as requested.`,\n {},\n )\n ).text;\n return summary;\n}\n\nfunction search() {\n const cache: Record<string, Awaited<ReturnType<typeof retrieve>>> = {};\n const processedSources = new Set<string>();\n return async (queries: string[]) => {\n const results: Awaited<ReturnType<typeof retrieve>>[] = [];\n for (const query of queries) {\n if (!cache[query]) {\n const res = await retrieve(query);\n cache[query] = uniqBy(res, (it) => it.source);\n }\n results.push(cache[query]);\n }\n const uniqueLinks: Record<string, string> = {};\n for (let i = 0; i < results.length; i++) {\n const query = queries[i];\n for (const item of results[i]) {\n if (!uniqueLinks[item.source] && !processedSources.has(item.source)) {\n uniqueLinks[item.source] = query;\n processedSources.add(item.source);\n }\n }\n }\n return uniqueLinks;\n };\n}\n\nif (import.meta.main) {\n const userQuery = 'How do we process payment?';\n\n const formatting = `\n1. use ascii markdown diagrams to illustrate. I am visual learner and I love markdown.\n2. use \"user stories\" to illustrate flows. we are not looking for only text or techical explanation.\n3. user story scenario should be divided by actors and steps.\n4. when referencing code snippets, include file path.\n`;\n\n const iterLimit = 2;\n const aggregatedContexts: string[] = [];\n const allSearchQueries: string[] = [];\n let iteration = 0;\n const repoContext = await gatherRepoContext();\n let searchQueriesResult = await generateSearchQueries(userQuery, repoContext);\n const performSearch = search();\n\n while (iteration < iterLimit) {\n const iterationContexts: string[] = [];\n\n allSearchQueries.push(...searchQueriesResult);\n const searchResults = await performSearch(searchQueriesResult);\n\n await Promise.all(\n Object.entries(searchResults).map(async ([source, query]) => {\n const context = await processFile(source, userQuery, query);\n if (context) {\n iterationContexts.push(\n `Source: ${context.source}\\n\\nContent: ${context.content}\\n\\n`,\n );\n }\n }),\n );\n\n if (iterationContexts.length === 0) {\n console.log('No useful contexts were found in this iteration.');\n } else {\n aggregatedContexts.push(...iterationContexts);\n }\n\n searchQueriesResult = await getNewSearchQueries(\n userQuery,\n allSearchQueries,\n aggregatedContexts,\n repoContext,\n );\n if (searchQueriesResult.length === 0) {\n console.log('No further research needed. Exiting loop.');\n break;\n } else {\n allSearchQueries.push(...searchQueriesResult);\n }\n\n iteration += 1;\n }\n\n console.log('\\nGenerating final report...');\n console.log('Search queries performed:', allSearchQueries);\n const finalReport = await generateFinalReport(\n userQuery,\n formatting,\n aggregatedContexts,\n );\n\n await writeFile('final_report.md', finalReport);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// packages/orchestrator/src/lib/deepresearch.v1.ts
|
|
2
|
+
import { groq } from "@ai-sdk/groq";
|
|
3
|
+
import { openai } from "@ai-sdk/openai";
|
|
4
|
+
import { tavily } from "@tavily/core";
|
|
5
|
+
import { writeFile } from "node:fs/promises";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { agent, execute, generate, input, user } from "@deepagents/agent";
|
|
8
|
+
function dedupeSearchEntries(entries) {
|
|
9
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10
|
+
const result = [];
|
|
11
|
+
for (const e of entries) {
|
|
12
|
+
const key = `${e.query}::${e.url ?? e.title}`;
|
|
13
|
+
if (!seen.has(key)) {
|
|
14
|
+
seen.add(key);
|
|
15
|
+
result.push(e);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
var OutlineOutputSchema = z.object({
|
|
21
|
+
reportTitle: z.string().min(5),
|
|
22
|
+
sections: z.array(
|
|
23
|
+
z.object({
|
|
24
|
+
title: z.string().min(1),
|
|
25
|
+
content: z.string().min(1)
|
|
26
|
+
})
|
|
27
|
+
).min(1).max(30)
|
|
28
|
+
});
|
|
29
|
+
var outlineAgent = agent({
|
|
30
|
+
name: "outline-planner",
|
|
31
|
+
model: groq("openai/gpt-oss-20b"),
|
|
32
|
+
prompt: [
|
|
33
|
+
"You are a Deep Research assistant. Given the USER QUERY, plan a structured report outline.",
|
|
34
|
+
"Return ONLY valid JSON (array of objects) matching the provided schema with paragraph title and content description.",
|
|
35
|
+
"Do not include code fences, commentary or reasoning, just JSON."
|
|
36
|
+
],
|
|
37
|
+
output: OutlineOutputSchema
|
|
38
|
+
});
|
|
39
|
+
var FirstSearchOutputSchema = z.object({
|
|
40
|
+
search_query: z.string().min(2),
|
|
41
|
+
reasoning: z.string().optional()
|
|
42
|
+
});
|
|
43
|
+
var firstSearchPlannerAgent = agent({
|
|
44
|
+
name: "first-search-planner",
|
|
45
|
+
model: groq("openai/gpt-oss-20b"),
|
|
46
|
+
prompt: `You are a Deep Research assistant. Given the USER QUERY plus paragraph title and initial content, craft ONE optimal web search query to collect factual, current information. Return only JSON {"search_query": string, "reasoning": string}.`,
|
|
47
|
+
output: FirstSearchOutputSchema
|
|
48
|
+
});
|
|
49
|
+
var ReflectionSearchOutputSchema = z.object({
|
|
50
|
+
search_query: z.string().min(2),
|
|
51
|
+
reasoning: z.string().optional()
|
|
52
|
+
});
|
|
53
|
+
var reflectionSearchPlannerAgent = agent({
|
|
54
|
+
name: "reflection-search-planner",
|
|
55
|
+
model: groq("openai/gpt-oss-20b"),
|
|
56
|
+
prompt: [
|
|
57
|
+
"You enrich a paragraph through iterative research. Provided JSON includes the USER QUERY, paragraph title, planned content, and the current drafted summary.",
|
|
58
|
+
"Identify a missing angle, fact, statistic, counterpoint, timeline, cause/effect, or recent development.",
|
|
59
|
+
'Return ONLY JSON {"search_query": string, "reasoning": string}. If no enrichment needed, use an empty string for search_query.'
|
|
60
|
+
],
|
|
61
|
+
output: ReflectionSearchOutputSchema
|
|
62
|
+
});
|
|
63
|
+
var ParagraphSummaryOutputSchema = z.object({
|
|
64
|
+
paragraph_latest_state: z.string().min(20)
|
|
65
|
+
});
|
|
66
|
+
var paragraphSummaryAgent = agent({
|
|
67
|
+
name: "paragraph-summarizer",
|
|
68
|
+
model: openai("gpt-4.1-mini"),
|
|
69
|
+
prompt: [
|
|
70
|
+
"You are producing a polished paragraph for a research report. Input JSON provides: USER QUERY, title, planned content, search_query used, and an array of textual snippets (search_results).",
|
|
71
|
+
"Integrate facts cohesively, avoid fluff, cite NO sources inline, keep within ~250 words, maintain factual tone.",
|
|
72
|
+
'Return ONLY JSON {"paragraph_latest_state": string}.'
|
|
73
|
+
],
|
|
74
|
+
output: ParagraphSummaryOutputSchema
|
|
75
|
+
});
|
|
76
|
+
var finalReportAgent = agent({
|
|
77
|
+
name: "final_report",
|
|
78
|
+
model: openai("gpt-4.1"),
|
|
79
|
+
prompt: (context) => `
|
|
80
|
+
You have finalized paragraphs of a research report as JSON array [{title, paragraph_latest_state}].
|
|
81
|
+
Produce a well-structured Markdown report with: top-level title, table of contents, each section with heading, and a concluding synthesis (add Conclusion if missing).
|
|
82
|
+
Do not hallucinate new sections beyond conclusion. Keep formatting clean.
|
|
83
|
+
`
|
|
84
|
+
});
|
|
85
|
+
async function planOutline(userQuery) {
|
|
86
|
+
const { output } = await generate(
|
|
87
|
+
outlineAgent,
|
|
88
|
+
`USER QUERY: ${userQuery}`,
|
|
89
|
+
{}
|
|
90
|
+
);
|
|
91
|
+
const result = output;
|
|
92
|
+
return {
|
|
93
|
+
reportTitle: result.reportTitle,
|
|
94
|
+
paragraphs: result.sections.map(
|
|
95
|
+
(p) => ({
|
|
96
|
+
title: p.title.trim(),
|
|
97
|
+
content: p.content.trim(),
|
|
98
|
+
research: {
|
|
99
|
+
latestSummary: "",
|
|
100
|
+
reflectionIteration: 0,
|
|
101
|
+
searchHistory: []
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function planFirstSearch(userQuery, paragraph) {
|
|
108
|
+
const { output } = await generate(
|
|
109
|
+
firstSearchPlannerAgent,
|
|
110
|
+
[
|
|
111
|
+
user(
|
|
112
|
+
`USER QUERY: ${userQuery}
|
|
113
|
+
Title: ${paragraph.title}
|
|
114
|
+
Content: ${paragraph.content}`
|
|
115
|
+
)
|
|
116
|
+
],
|
|
117
|
+
{ userQuery }
|
|
118
|
+
);
|
|
119
|
+
return output;
|
|
120
|
+
}
|
|
121
|
+
async function planReflectionSearch(userQuery, paragraph) {
|
|
122
|
+
const { output } = await generate(
|
|
123
|
+
reflectionSearchPlannerAgent,
|
|
124
|
+
`USER QUERY: ${userQuery}
|
|
125
|
+
${JSON.stringify({
|
|
126
|
+
title: paragraph.title,
|
|
127
|
+
content: paragraph.content,
|
|
128
|
+
paragraph_latest_state: paragraph.research.latestSummary
|
|
129
|
+
})}`,
|
|
130
|
+
{ userQuery }
|
|
131
|
+
);
|
|
132
|
+
return output;
|
|
133
|
+
}
|
|
134
|
+
async function summarizeParagraph(userQuery, paragraph, searchQuery, snippets) {
|
|
135
|
+
const input2 = {
|
|
136
|
+
user_query: userQuery,
|
|
137
|
+
title: paragraph.title,
|
|
138
|
+
content: paragraph.content,
|
|
139
|
+
search_query: searchQuery,
|
|
140
|
+
search_results: snippets.slice(0, 8)
|
|
141
|
+
};
|
|
142
|
+
const { output } = await generate(
|
|
143
|
+
paragraphSummaryAgent,
|
|
144
|
+
[
|
|
145
|
+
user(
|
|
146
|
+
`
|
|
147
|
+
USER QUERY: ${userQuery}
|
|
148
|
+
Title: ${input2.title}
|
|
149
|
+
Content: ${input2.content}
|
|
150
|
+
Search Query: ${input2.search_query}
|
|
151
|
+
Search Results: ${input2.search_results.join("\n\n---\n\n")}
|
|
152
|
+
`
|
|
153
|
+
)
|
|
154
|
+
],
|
|
155
|
+
{ userQuery }
|
|
156
|
+
);
|
|
157
|
+
const out = output;
|
|
158
|
+
paragraph.research.latestSummary = out.paragraph_latest_state.trim();
|
|
159
|
+
}
|
|
160
|
+
async function runWebSearch(query) {
|
|
161
|
+
const tvly = tavily();
|
|
162
|
+
const response = await tvly.search(query);
|
|
163
|
+
return response.results.map(
|
|
164
|
+
(r) => ({
|
|
165
|
+
query,
|
|
166
|
+
url: r.url,
|
|
167
|
+
title: r.title,
|
|
168
|
+
content: r.content
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
function collectAllSnippets(p) {
|
|
173
|
+
return p.research.searchHistory.map((h) => h.content?.trim()).filter((s) => !!s);
|
|
174
|
+
}
|
|
175
|
+
var defaultResearchOptions = {
|
|
176
|
+
maxReflections: 2,
|
|
177
|
+
stopOnDuplicateQuery: true
|
|
178
|
+
};
|
|
179
|
+
async function researchParagraph(userQuery, paragraph, options = {}) {
|
|
180
|
+
const opts = { ...defaultResearchOptions, ...options };
|
|
181
|
+
const firstPlan = await planFirstSearch(userQuery, paragraph);
|
|
182
|
+
console.log(`
|
|
183
|
+
=== Researching Paragraph: ${paragraph.title} ===`);
|
|
184
|
+
console.log(
|
|
185
|
+
`Search Query: ${firstPlan.search_query} with reasoning: ${firstPlan.reasoning}`
|
|
186
|
+
);
|
|
187
|
+
const firstQuery = firstPlan.search_query?.trim();
|
|
188
|
+
if (!firstQuery) return;
|
|
189
|
+
const firstResults = await runWebSearch(firstQuery);
|
|
190
|
+
paragraph.research.searchHistory.push(...firstResults);
|
|
191
|
+
paragraph.research.searchHistory = dedupeSearchEntries(
|
|
192
|
+
paragraph.research.searchHistory
|
|
193
|
+
);
|
|
194
|
+
await summarizeParagraph(
|
|
195
|
+
userQuery,
|
|
196
|
+
paragraph,
|
|
197
|
+
firstQuery,
|
|
198
|
+
collectAllSnippets(paragraph)
|
|
199
|
+
);
|
|
200
|
+
while (paragraph.research.reflectionIteration < opts.maxReflections) {
|
|
201
|
+
const reflection = await planReflectionSearch(userQuery, paragraph);
|
|
202
|
+
const rq = reflection.search_query?.trim();
|
|
203
|
+
if (!rq) break;
|
|
204
|
+
const alreadyUsed = paragraph.research.searchHistory.some(
|
|
205
|
+
(h) => h.query.toLowerCase() === rq.toLowerCase()
|
|
206
|
+
);
|
|
207
|
+
if (alreadyUsed && opts.stopOnDuplicateQuery) break;
|
|
208
|
+
const refResults = await runWebSearch(rq);
|
|
209
|
+
paragraph.research.searchHistory.push(...refResults);
|
|
210
|
+
paragraph.research.searchHistory = dedupeSearchEntries(
|
|
211
|
+
paragraph.research.searchHistory
|
|
212
|
+
);
|
|
213
|
+
paragraph.research.reflectionIteration += 1;
|
|
214
|
+
await summarizeParagraph(
|
|
215
|
+
userQuery,
|
|
216
|
+
paragraph,
|
|
217
|
+
rq,
|
|
218
|
+
collectAllSnippets(paragraph)
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async function deepresearch(userQuery, options = {}) {
|
|
223
|
+
const state = await planOutline(userQuery);
|
|
224
|
+
for (let i = 0; i < state.paragraphs.length; i++) {
|
|
225
|
+
await researchParagraph(userQuery, state.paragraphs[i], options);
|
|
226
|
+
}
|
|
227
|
+
const reportData = state.paragraphs.map((p) => ({
|
|
228
|
+
title: p.title,
|
|
229
|
+
paragraph_latest_state: p.research.latestSummary
|
|
230
|
+
}));
|
|
231
|
+
const result = await execute(
|
|
232
|
+
finalReportAgent,
|
|
233
|
+
[
|
|
234
|
+
user(
|
|
235
|
+
`User Query: ${userQuery}
|
|
236
|
+
Formatting: use ascii markdown diagrams to illustrate. I am visual learner and I love markdown.
|
|
237
|
+
Context: ${reportData.join("\n\n")}`
|
|
238
|
+
)
|
|
239
|
+
],
|
|
240
|
+
{ userQuery }
|
|
241
|
+
);
|
|
242
|
+
const finalReportMd = await result.text;
|
|
243
|
+
return { state, markdown: finalReportMd };
|
|
244
|
+
}
|
|
245
|
+
if (import.meta.main) {
|
|
246
|
+
const userQuery = await input(
|
|
247
|
+
"How to integrates planning modules from whitepaper like LLM Compiler, plan and solve, plan and act and others into building deepresearch agent?"
|
|
248
|
+
);
|
|
249
|
+
const { state, markdown } = await deepresearch(userQuery, {
|
|
250
|
+
maxReflections: 1
|
|
251
|
+
});
|
|
252
|
+
const outfile = `deepresearch_report.md`;
|
|
253
|
+
await writeFile(outfile, markdown, "utf8");
|
|
254
|
+
console.dir(state, { depth: null });
|
|
255
|
+
}
|
|
256
|
+
export {
|
|
257
|
+
deepresearch,
|
|
258
|
+
researchParagraph
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=deepresearch.v1.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/deepresearch.v1.ts"],
|
|
4
|
+
"sourcesContent": ["import { groq } from '@ai-sdk/groq';\nimport { openai } from '@ai-sdk/openai';\nimport { tavily } from '@tavily/core';\nimport { writeFile } from 'node:fs/promises';\nimport { z } from 'zod';\n\nimport { agent, execute, generate, input, user } from '@deepagents/agent';\n\nexport interface SearchEntry {\n title: string;\n url: string;\n content: string;\n query: string;\n}\n\nexport interface ParagraphResearchState {\n searchHistory: SearchEntry[]; // appended chronologically\n latestSummary: string; // evolving synthesized paragraph content\n reflectionIteration: number; // count of reflection loops executed\n}\n\nexport interface ParagraphPlan {\n title: string;\n content: string; // planned description / intent for the paragraph\n research: ParagraphResearchState;\n}\n\nexport interface ResearchState {\n reportTitle: string;\n paragraphs: ParagraphPlan[];\n}\n\nfunction dedupeSearchEntries(entries: SearchEntry[]): SearchEntry[] {\n const seen = new Set<string>();\n const result: SearchEntry[] = [];\n for (const e of entries) {\n const key = `${e.query}::${e.url ?? e.title}`;\n if (!seen.has(key)) {\n seen.add(key);\n result.push(e);\n }\n }\n return result;\n}\n\nconst OutlineOutputSchema = z.object({\n reportTitle: z.string().min(5),\n sections: z\n .array(\n z.object({\n title: z.string().min(1),\n content: z.string().min(1),\n }),\n )\n .min(1)\n .max(30),\n});\n\nconst outlineAgent = agent({\n name: 'outline-planner',\n model: groq('openai/gpt-oss-20b'),\n prompt: [\n 'You are a Deep Research assistant. Given the USER QUERY, plan a structured report outline.',\n 'Return ONLY valid JSON (array of objects) matching the provided schema with paragraph title and content description.',\n 'Do not include code fences, commentary or reasoning, just JSON.',\n ],\n output: OutlineOutputSchema,\n});\n\nconst FirstSearchOutputSchema = z.object({\n search_query: z.string().min(2),\n reasoning: z.string().optional(),\n});\n\nconst firstSearchPlannerAgent = agent({\n name: 'first-search-planner',\n model: groq('openai/gpt-oss-20b'),\n prompt: `You are a Deep Research assistant. Given the USER QUERY plus paragraph title and initial content, craft ONE optimal web search query to collect factual, current information. Return only JSON {\"search_query\": string, \"reasoning\": string}.`,\n output: FirstSearchOutputSchema,\n});\n\nconst ReflectionSearchOutputSchema = z.object({\n search_query: z.string().min(2),\n reasoning: z.string().optional(),\n});\n\nconst reflectionSearchPlannerAgent = agent({\n name: 'reflection-search-planner',\n model: groq('openai/gpt-oss-20b'),\n prompt: [\n 'You enrich a paragraph through iterative research. Provided JSON includes the USER QUERY, paragraph title, planned content, and the current drafted summary.',\n 'Identify a missing angle, fact, statistic, counterpoint, timeline, cause/effect, or recent development.',\n 'Return ONLY JSON {\"search_query\": string, \"reasoning\": string}. If no enrichment needed, use an empty string for search_query.',\n ],\n output: ReflectionSearchOutputSchema,\n});\n\nconst ParagraphSummaryOutputSchema = z.object({\n paragraph_latest_state: z.string().min(20),\n});\n\nconst paragraphSummaryAgent = agent({\n name: 'paragraph-summarizer',\n model: openai('gpt-4.1-mini'),\n prompt: [\n 'You are producing a polished paragraph for a research report. Input JSON provides: USER QUERY, title, planned content, search_query used, and an array of textual snippets (search_results).',\n 'Integrate facts cohesively, avoid fluff, cite NO sources inline, keep within ~250 words, maintain factual tone.',\n 'Return ONLY JSON {\"paragraph_latest_state\": string}.',\n ],\n output: ParagraphSummaryOutputSchema,\n});\n\nconst finalReportAgent = agent<{ userQuery: string }>({\n name: 'final_report',\n model: openai('gpt-4.1'),\n prompt: (context) => `\n\t\tYou have finalized paragraphs of a research report as JSON array [{title, paragraph_latest_state}].\n Produce a well-structured Markdown report with: top-level title, table of contents, each section with heading, and a concluding synthesis (add Conclusion if missing).\n Do not hallucinate new sections beyond conclusion. Keep formatting clean.\n `,\n});\n\ntype OutlineOutput = z.infer<typeof OutlineOutputSchema>;\n\nasync function planOutline(userQuery: string) {\n const { output } = await generate(\n outlineAgent,\n `USER QUERY: ${userQuery}`,\n {},\n );\n const result = output as OutlineOutput;\n return {\n reportTitle: result.reportTitle,\n paragraphs: result.sections.map(\n (p: { title: string; content: string }) => ({\n title: p.title.trim(),\n content: p.content.trim(),\n research: {\n latestSummary: '',\n reflectionIteration: 0,\n searchHistory: [],\n },\n }),\n ),\n } satisfies ResearchState;\n}\n\ntype FirstSearchOutput = z.infer<typeof FirstSearchOutputSchema>;\n\nasync function planFirstSearch(userQuery: string, paragraph: ParagraphPlan) {\n const { output } = await generate(\n firstSearchPlannerAgent,\n [\n user(\n `USER QUERY: ${userQuery}\\nTitle: ${paragraph.title}\\nContent: ${paragraph.content}`,\n ),\n ],\n { userQuery },\n );\n return output as FirstSearchOutput;\n}\n\ntype ReflectionSearchOutput = z.infer<typeof ReflectionSearchOutputSchema>;\n\nasync function planReflectionSearch(\n userQuery: string,\n paragraph: ParagraphPlan,\n) {\n const { output } = await generate(\n reflectionSearchPlannerAgent,\n `USER QUERY: ${userQuery}\\n${JSON.stringify({\n title: paragraph.title,\n content: paragraph.content,\n paragraph_latest_state: paragraph.research.latestSummary,\n })}`,\n { userQuery },\n );\n return output as ReflectionSearchOutput;\n}\n\nasync function summarizeParagraph(\n userQuery: string,\n paragraph: ParagraphPlan,\n searchQuery: string,\n snippets: string[],\n) {\n const input = {\n user_query: userQuery,\n title: paragraph.title,\n content: paragraph.content,\n search_query: searchQuery,\n search_results: snippets.slice(0, 8),\n };\n type ParagraphSummaryOutput = z.infer<typeof ParagraphSummaryOutputSchema>;\n const { output } = await generate(\n paragraphSummaryAgent,\n [\n user(\n `\n\t\t\t\tUSER QUERY: ${userQuery}\n\t\t\t\tTitle: ${input.title}\n\t\t\t\tContent: ${input.content}\n\t\t\t\tSearch Query: ${input.search_query}\n\t\t\t\tSearch Results: ${input.search_results.join('\\n\\n---\\n\\n')}\n\t\t\t\t`,\n ),\n ],\n { userQuery },\n );\n const out = output as ParagraphSummaryOutput;\n paragraph.research.latestSummary = out.paragraph_latest_state.trim();\n}\n\nasync function runWebSearch(query: string) {\n const tvly = tavily();\n const response = await tvly.search(query);\n return response.results.map(\n (r) =>\n ({\n query,\n url: r.url,\n title: r.title,\n content: r.content,\n }) satisfies SearchEntry,\n );\n}\n\nfunction collectAllSnippets(p: ParagraphPlan): string[] {\n return p.research.searchHistory\n .map((h) => h.content?.trim())\n .filter((s): s is string => !!s);\n}\n\nexport interface ResearchOptions {\n maxReflections?: number; // per paragraph\n stopOnDuplicateQuery?: boolean;\n}\n\nconst defaultResearchOptions: Required<ResearchOptions> = {\n maxReflections: 2,\n stopOnDuplicateQuery: true,\n};\n\nexport async function researchParagraph(\n userQuery: string,\n paragraph: ParagraphPlan,\n options: ResearchOptions = {},\n) {\n const opts = { ...defaultResearchOptions, ...options };\n const firstPlan = await planFirstSearch(userQuery, paragraph);\n console.log(`\\n=== Researching Paragraph: ${paragraph.title} ===`);\n console.log(\n `Search Query: ${firstPlan.search_query} with reasoning: ${firstPlan.reasoning}`,\n );\n const firstQuery = firstPlan.search_query?.trim();\n if (!firstQuery) return;\n const firstResults = await runWebSearch(firstQuery);\n paragraph.research.searchHistory.push(...firstResults);\n paragraph.research.searchHistory = dedupeSearchEntries(\n paragraph.research.searchHistory,\n );\n await summarizeParagraph(\n userQuery,\n paragraph,\n firstQuery,\n collectAllSnippets(paragraph),\n );\n\n // Reflection loop\n while (paragraph.research.reflectionIteration < opts.maxReflections) {\n const reflection = await planReflectionSearch(userQuery, paragraph);\n const rq = reflection.search_query?.trim();\n if (!rq) break; // model decided no more\n const alreadyUsed = paragraph.research.searchHistory.some(\n (h) => h.query.toLowerCase() === rq.toLowerCase(),\n );\n if (alreadyUsed && opts.stopOnDuplicateQuery) break;\n\n const refResults = await runWebSearch(rq);\n paragraph.research.searchHistory.push(...refResults);\n paragraph.research.searchHistory = dedupeSearchEntries(\n paragraph.research.searchHistory,\n );\n paragraph.research.reflectionIteration += 1;\n await summarizeParagraph(\n userQuery,\n paragraph,\n rq,\n collectAllSnippets(paragraph),\n );\n }\n}\n\nexport async function deepresearch(\n userQuery: string,\n options: ResearchOptions = {},\n): Promise<{ state: ResearchState; markdown: string }> {\n const state = await planOutline(userQuery);\n for (let i = 0; i < state.paragraphs.length; i++) {\n await researchParagraph(userQuery, state.paragraphs[i], options);\n }\n const reportData = state.paragraphs.map((p) => ({\n title: p.title,\n paragraph_latest_state: p.research.latestSummary,\n }));\n const result = await execute(\n finalReportAgent,\n [\n user(\n `User Query: ${userQuery}\\nFormatting: use ascii markdown diagrams to illustrate. I am visual learner and I love markdown.\\nContext: ${reportData.join('\\n\\n')}`,\n ),\n ],\n { userQuery },\n );\n const finalReportMd = await result.text;\n return { state, markdown: finalReportMd };\n}\n\nif (import.meta.main) {\n const userQuery = await input(\n 'How to integrates planning modules from whitepaper like LLM Compiler, plan and solve, plan and act and others into building deepresearch agent?',\n );\n const { state, markdown } = await deepresearch(userQuery, {\n maxReflections: 1,\n });\n const outfile = `deepresearch_report.md`;\n await writeFile(outfile, markdown, 'utf8');\n console.dir(state, { depth: null });\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAC1B,SAAS,SAAS;AAElB,SAAS,OAAO,SAAS,UAAU,OAAO,YAAY;AA0BtD,SAAS,oBAAoB,SAAuC;AAClE,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAwB,CAAC;AAC/B,aAAW,KAAK,SAAS;AACvB,UAAM,MAAM,GAAG,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE,KAAK;AAC3C,QAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,WAAK,IAAI,GAAG;AACZ,aAAO,KAAK,CAAC;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,UAAU,EACP;AAAA,IACC,EAAE,OAAO;AAAA,MACP,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MACvB,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC3B,CAAC;AAAA,EACH,EACC,IAAI,CAAC,EACL,IAAI,EAAE;AACX,CAAC;AAED,IAAM,eAAe,MAAM;AAAA,EACzB,MAAM;AAAA,EACN,OAAO,KAAK,oBAAoB;AAAA,EAChC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AACV,CAAC;AAED,IAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,WAAW,EAAE,OAAO,EAAE,SAAS;AACjC,CAAC;AAED,IAAM,0BAA0B,MAAM;AAAA,EACpC,MAAM;AAAA,EACN,OAAO,KAAK,oBAAoB;AAAA,EAChC,QAAQ;AAAA,EACR,QAAQ;AACV,CAAC;AAED,IAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,WAAW,EAAE,OAAO,EAAE,SAAS;AACjC,CAAC;AAED,IAAM,+BAA+B,MAAM;AAAA,EACzC,MAAM;AAAA,EACN,OAAO,KAAK,oBAAoB;AAAA,EAChC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AACV,CAAC;AAED,IAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,wBAAwB,EAAE,OAAO,EAAE,IAAI,EAAE;AAC3C,CAAC;AAED,IAAM,wBAAwB,MAAM;AAAA,EAClC,MAAM;AAAA,EACN,OAAO,OAAO,cAAc;AAAA,EAC5B,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AACV,CAAC;AAED,IAAM,mBAAmB,MAA6B;AAAA,EACpD,MAAM;AAAA,EACN,OAAO,OAAO,SAAS;AAAA,EACvB,QAAQ,CAAC,YAAY;AAAA;AAAA;AAAA;AAAA;AAKvB,CAAC;AAID,eAAe,YAAY,WAAmB;AAC5C,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,IACA,eAAe,SAAS;AAAA,IACxB,CAAC;AAAA,EACH;AACA,QAAM,SAAS;AACf,SAAO;AAAA,IACL,aAAa,OAAO;AAAA,IACpB,YAAY,OAAO,SAAS;AAAA,MAC1B,CAAC,OAA2C;AAAA,QAC1C,OAAO,EAAE,MAAM,KAAK;AAAA,QACpB,SAAS,EAAE,QAAQ,KAAK;AAAA,QACxB,UAAU;AAAA,UACR,eAAe;AAAA,UACf,qBAAqB;AAAA,UACrB,eAAe,CAAC;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAIA,eAAe,gBAAgB,WAAmB,WAA0B;AAC1E,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,IACA;AAAA,MACE;AAAA,QACE,eAAe,SAAS;AAAA,SAAY,UAAU,KAAK;AAAA,WAAc,UAAU,OAAO;AAAA,MACpF;AAAA,IACF;AAAA,IACA,EAAE,UAAU;AAAA,EACd;AACA,SAAO;AACT;AAIA,eAAe,qBACb,WACA,WACA;AACA,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,IACA,eAAe,SAAS;AAAA,EAAK,KAAK,UAAU;AAAA,MAC1C,OAAO,UAAU;AAAA,MACjB,SAAS,UAAU;AAAA,MACnB,wBAAwB,UAAU,SAAS;AAAA,IAC7C,CAAC,CAAC;AAAA,IACF,EAAE,UAAU;AAAA,EACd;AACA,SAAO;AACT;AAEA,eAAe,mBACb,WACA,WACA,aACA,UACA;AACA,QAAMA,SAAQ;AAAA,IACZ,YAAY;AAAA,IACZ,OAAO,UAAU;AAAA,IACjB,SAAS,UAAU;AAAA,IACnB,cAAc;AAAA,IACd,gBAAgB,SAAS,MAAM,GAAG,CAAC;AAAA,EACrC;AAEA,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,IACA;AAAA,MACE;AAAA,QACE;AAAA,kBACU,SAAS;AAAA,aACdA,OAAM,KAAK;AAAA,eACTA,OAAM,OAAO;AAAA,oBACRA,OAAM,YAAY;AAAA,sBAChBA,OAAM,eAAe,KAAK,aAAa,CAAC;AAAA;AAAA,MAExD;AAAA,IACF;AAAA,IACA,EAAE,UAAU;AAAA,EACd;AACA,QAAM,MAAM;AACZ,YAAU,SAAS,gBAAgB,IAAI,uBAAuB,KAAK;AACrE;AAEA,eAAe,aAAa,OAAe;AACzC,QAAM,OAAO,OAAO;AACpB,QAAM,WAAW,MAAM,KAAK,OAAO,KAAK;AACxC,SAAO,SAAS,QAAQ;AAAA,IACtB,CAAC,OACE;AAAA,MACC;AAAA,MACA,KAAK,EAAE;AAAA,MACP,OAAO,EAAE;AAAA,MACT,SAAS,EAAE;AAAA,IACb;AAAA,EACJ;AACF;AAEA,SAAS,mBAAmB,GAA4B;AACtD,SAAO,EAAE,SAAS,cACf,IAAI,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,EAC5B,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AACnC;AAOA,IAAM,yBAAoD;AAAA,EACxD,gBAAgB;AAAA,EAChB,sBAAsB;AACxB;AAEA,eAAsB,kBACpB,WACA,WACA,UAA2B,CAAC,GAC5B;AACA,QAAM,OAAO,EAAE,GAAG,wBAAwB,GAAG,QAAQ;AACrD,QAAM,YAAY,MAAM,gBAAgB,WAAW,SAAS;AAC5D,UAAQ,IAAI;AAAA,6BAAgC,UAAU,KAAK,MAAM;AACjE,UAAQ;AAAA,IACN,iBAAiB,UAAU,YAAY,oBAAoB,UAAU,SAAS;AAAA,EAChF;AACA,QAAM,aAAa,UAAU,cAAc,KAAK;AAChD,MAAI,CAAC,WAAY;AACjB,QAAM,eAAe,MAAM,aAAa,UAAU;AAClD,YAAU,SAAS,cAAc,KAAK,GAAG,YAAY;AACrD,YAAU,SAAS,gBAAgB;AAAA,IACjC,UAAU,SAAS;AAAA,EACrB;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,SAAS;AAAA,EAC9B;AAGA,SAAO,UAAU,SAAS,sBAAsB,KAAK,gBAAgB;AACnE,UAAM,aAAa,MAAM,qBAAqB,WAAW,SAAS;AAClE,UAAM,KAAK,WAAW,cAAc,KAAK;AACzC,QAAI,CAAC,GAAI;AACT,UAAM,cAAc,UAAU,SAAS,cAAc;AAAA,MACnD,CAAC,MAAM,EAAE,MAAM,YAAY,MAAM,GAAG,YAAY;AAAA,IAClD;AACA,QAAI,eAAe,KAAK,qBAAsB;AAE9C,UAAM,aAAa,MAAM,aAAa,EAAE;AACxC,cAAU,SAAS,cAAc,KAAK,GAAG,UAAU;AACnD,cAAU,SAAS,gBAAgB;AAAA,MACjC,UAAU,SAAS;AAAA,IACrB;AACA,cAAU,SAAS,uBAAuB;AAC1C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,SAAS;AAAA,IAC9B;AAAA,EACF;AACF;AAEA,eAAsB,aACpB,WACA,UAA2B,CAAC,GACyB;AACrD,QAAM,QAAQ,MAAM,YAAY,SAAS;AACzC,WAAS,IAAI,GAAG,IAAI,MAAM,WAAW,QAAQ,KAAK;AAChD,UAAM,kBAAkB,WAAW,MAAM,WAAW,CAAC,GAAG,OAAO;AAAA,EACjE;AACA,QAAM,aAAa,MAAM,WAAW,IAAI,CAAC,OAAO;AAAA,IAC9C,OAAO,EAAE;AAAA,IACT,wBAAwB,EAAE,SAAS;AAAA,EACrC,EAAE;AACF,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,MACE;AAAA,QACE,eAAe,SAAS;AAAA;AAAA,WAA+G,WAAW,KAAK,MAAM,CAAC;AAAA,MAChK;AAAA,IACF;AAAA,IACA,EAAE,UAAU;AAAA,EACd;AACA,QAAM,gBAAgB,MAAM,OAAO;AACnC,SAAO,EAAE,OAAO,UAAU,cAAc;AAC1C;AAEA,IAAI,YAAY,MAAM;AACpB,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,EACF;AACA,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,aAAa,WAAW;AAAA,IACxD,gBAAgB;AAAA,EAClB,CAAC;AACD,QAAM,UAAU;AAChB,QAAM,UAAU,SAAS,UAAU,MAAM;AACzC,UAAQ,IAAI,OAAO,EAAE,OAAO,KAAK,CAAC;AACpC;",
|
|
6
|
+
"names": ["input"]
|
|
7
|
+
}
|