@moxxy/mode-deep-research 0.26.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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/dist/approval.d.ts +32 -0
  3. package/dist/approval.d.ts.map +1 -0
  4. package/dist/approval.js +84 -0
  5. package/dist/approval.js.map +1 -0
  6. package/dist/constants.d.ts +62 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +141 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/fanout-phase.d.ts +44 -0
  11. package/dist/fanout-phase.d.ts.map +1 -0
  12. package/dist/fanout-phase.js +133 -0
  13. package/dist/fanout-phase.js.map +1 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +18 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/parse-queries.d.ts +13 -0
  19. package/dist/parse-queries.d.ts.map +1 -0
  20. package/dist/parse-queries.js +71 -0
  21. package/dist/parse-queries.js.map +1 -0
  22. package/dist/query-phase.d.ts +15 -0
  23. package/dist/query-phase.d.ts.map +1 -0
  24. package/dist/query-phase.js +81 -0
  25. package/dist/query-phase.js.map +1 -0
  26. package/dist/research-loop.d.ts +18 -0
  27. package/dist/research-loop.d.ts.map +1 -0
  28. package/dist/research-loop.js +357 -0
  29. package/dist/research-loop.js.map +1 -0
  30. package/dist/synthesis-phase.d.ts +8 -0
  31. package/dist/synthesis-phase.d.ts.map +1 -0
  32. package/dist/synthesis-phase.js +21 -0
  33. package/dist/synthesis-phase.js.map +1 -0
  34. package/package.json +73 -0
  35. package/src/approval.test.ts +82 -0
  36. package/src/approval.ts +105 -0
  37. package/src/constants.ts +153 -0
  38. package/src/fanout-phase.ts +177 -0
  39. package/src/index.test.ts +575 -0
  40. package/src/index.ts +27 -0
  41. package/src/parse-queries.ts +72 -0
  42. package/src/query-phase.ts +123 -0
  43. package/src/research-loop.ts +414 -0
  44. package/src/synthesis-phase.ts +25 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moxxy (moxxy.ai)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,32 @@
1
+ import type { ModeContext } from '@moxxy/sdk';
2
+ export type QueryGateOutcome = {
3
+ kind: 'approve';
4
+ } | {
5
+ kind: 'redraft';
6
+ feedback: string | null;
7
+ } | {
8
+ kind: 'cancel';
9
+ } | {
10
+ kind: 'redraft-cap-exceeded';
11
+ };
12
+ /**
13
+ * Optional approval gate after the query plan is produced. Headless
14
+ * contexts (no resolver) auto-approve. Approve / redraft-with-feedback /
15
+ * cancel option ids, with bounded redraft retries.
16
+ */
17
+ export declare function runQueryApprovalGate(ctx: ModeContext, planText: string, queryCount: number, redraftCount: number): Promise<{
18
+ outcome: QueryGateOutcome;
19
+ redraftCount: number;
20
+ }>;
21
+ export type SynthesisGateOutcome = {
22
+ kind: 'synthesize';
23
+ } | {
24
+ kind: 'cancel';
25
+ };
26
+ /**
27
+ * Approval gate shown after fan-out, before the synthesis turn. Body is
28
+ * a short digest of each subagent's result so the user can sanity-check
29
+ * coverage before paying for synthesis tokens.
30
+ */
31
+ export declare function runSynthesisApprovalGate(ctx: ModeContext, digest: string): Promise<SynthesisGateOutcome>;
32
+ //# sourceMappingURL=approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../src/approval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAErC;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,OAAO,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CA4C9D;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvB;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,oBAAoB,CAAC,CA0B/B"}
@@ -0,0 +1,84 @@
1
+ import { MAX_REDRAFTS } from './constants.js';
2
+ /**
3
+ * Optional approval gate after the query plan is produced. Headless
4
+ * contexts (no resolver) auto-approve. Approve / redraft-with-feedback /
5
+ * cancel option ids, with bounded redraft retries.
6
+ */
7
+ export async function runQueryApprovalGate(ctx, planText, queryCount, redraftCount) {
8
+ if (!ctx.approval)
9
+ return { outcome: { kind: 'approve' }, redraftCount };
10
+ const decision = await ctx.approval.confirm({
11
+ title: 'Query plan ready — review before fan-out',
12
+ body: planText,
13
+ kind: 'deep-research.queries',
14
+ defaultOptionId: 'approve',
15
+ options: [
16
+ {
17
+ id: 'approve',
18
+ label: 'Approve and fan out',
19
+ hotkey: 'a',
20
+ description: `Spawn ${queryCount} parallel subagent${queryCount === 1 ? '' : 's'} to research these.`,
21
+ },
22
+ {
23
+ id: 'redraft',
24
+ label: 'Redraft with feedback',
25
+ hotkey: 'r',
26
+ requestsText: true,
27
+ textPrompt: 'What should change about the query plan?',
28
+ description: 'Send feedback to the planner and get a new query plan.',
29
+ },
30
+ {
31
+ id: 'cancel',
32
+ label: 'Cancel this turn',
33
+ hotkey: 'c',
34
+ danger: true,
35
+ },
36
+ ],
37
+ });
38
+ if (decision.optionId === 'cancel')
39
+ return { outcome: { kind: 'cancel' }, redraftCount };
40
+ if (decision.optionId === 'redraft') {
41
+ const nextCount = redraftCount + 1;
42
+ if (nextCount > MAX_REDRAFTS) {
43
+ return { outcome: { kind: 'redraft-cap-exceeded' }, redraftCount: nextCount };
44
+ }
45
+ return {
46
+ outcome: { kind: 'redraft', feedback: decision.text ?? null },
47
+ redraftCount: nextCount,
48
+ };
49
+ }
50
+ return { outcome: { kind: 'approve' }, redraftCount };
51
+ }
52
+ /**
53
+ * Approval gate shown after fan-out, before the synthesis turn. Body is
54
+ * a short digest of each subagent's result so the user can sanity-check
55
+ * coverage before paying for synthesis tokens.
56
+ */
57
+ export async function runSynthesisApprovalGate(ctx, digest) {
58
+ if (!ctx.approval)
59
+ return { kind: 'synthesize' };
60
+ const decision = await ctx.approval.confirm({
61
+ title: 'Fan-out complete — synthesize the final writeup?',
62
+ body: digest,
63
+ kind: 'deep-research.synthesis',
64
+ defaultOptionId: 'synthesize',
65
+ options: [
66
+ {
67
+ id: 'synthesize',
68
+ label: 'Synthesize',
69
+ hotkey: 's',
70
+ description: 'Combine the findings into the final writeup.',
71
+ },
72
+ {
73
+ id: 'cancel',
74
+ label: 'Cancel this turn',
75
+ hotkey: 'c',
76
+ danger: true,
77
+ },
78
+ ],
79
+ });
80
+ if (decision.optionId === 'cancel')
81
+ return { kind: 'cancel' };
82
+ return { kind: 'synthesize' };
83
+ }
84
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../src/approval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export declare const RESEARCH_MODE_NAME = "research";
2
+ export declare const DEEP_RESEARCH_PLUGIN_ID: import("@moxxy/sdk").PluginId;
3
+ /**
4
+ * Asked once in the planning phase. The subagents fan out IN PARALLEL —
5
+ * which means a query can never depend on another query's output. If we
6
+ * let the planner emit "compare side A and side B" or "what are the
7
+ * disputed claims" as separate queries, the subagent running them has
8
+ * no idea what was actually gathered and either invents content or
9
+ * gives up (e.g. "I can't determine what 'the disputed claims' refers
10
+ * to from the prompt alone"). The synthesis phase already sees every
11
+ * subagent's findings end-to-end and is where comparison + contradiction
12
+ * analysis belongs — the planner's job is purely to spread the raw
13
+ * gathering work across independent angles.
14
+ */
15
+ export declare const QUERY_PLAN_SYSTEM_PROMPT = "You are scoping a deep-research task. Produce 2-5 PARALLEL GATHERING queries \u2014 one per independent angle of raw evidence the synthesis phase will need.\n\nHARD RULES (the loop refuses plans that break these):\n- Each query MUST be independently answerable from web search + page reads ALONE \u2014 without seeing any other query's output. The subagents run in parallel and never see each other's findings.\n- DO NOT emit comparison, contradiction, \"differences\", \"disputed claims\", \"which side is right\", \"balanced timeline\", \"verify side X's claims\", or other queries that require knowing what OTHER queries returned. Those are the synthesis phase's job, not gathering.\n- DO NOT pad. If the user's question only needs 2 angles (e.g. \"compare X side vs Y side\"), emit exactly 2 queries \u2014 one per side. The synthesis turn does the comparison.\n- Each query should be concrete and scoped (\"What did <party> say about <topic> in the last 30 days?\"), not an open theme (\"Background on X\").\n- No two queries should be rephrasings of each other.\n\nReply with EXACTLY this format and nothing else:\n\nQUERIES:\n1. <gathering query>\n2. <gathering query>\n...\n\nStop after the last numbered line.";
16
+ /**
17
+ * System prompt for each fan-out subagent. They run in standard tool-use
18
+ * mode, but constrained (by allowedTools) to read-only web tools. The
19
+ * SOURCES: block is what the synthesis phase pulls citations from.
20
+ */
21
+ export declare const SUBAGENT_SYSTEM_PROMPT = "You are a focused research subagent. You have ONE sub-question to answer. Use web_search and web_fetch (and Read for any local files referenced) to gather evidence, then produce a concise writeup.\n\nStop tool-calling when you have enough material to answer. Reply with:\n\nFINDINGS:\n<2-4 short paragraphs answering the sub-question, citing sources inline like [1], [2] where claims come from a specific source>\n\nSOURCES:\n[1] <title> \u2014 <url>\n[2] <title> \u2014 <url>\n...\n\nDo NOT edit files. Do NOT run git. Stop after the last source line.";
22
+ /**
23
+ * Asked between fan-out rounds. Given the findings from the prior
24
+ * round(s), the model decides whether MORE parallel gathering is
25
+ * needed to fill specific gaps before synthesis — and if so, what.
26
+ * This is the "agentic" half of the loop that the user explicitly
27
+ * asked for: round-1 gathers Iran-side + USA-side, round-2 spawns
28
+ * follow-ups armed with both, instead of asking blind round-1
29
+ * subagents to compare things they can't see.
30
+ */
31
+ export declare const FOLLOWUP_PLAN_SYSTEM_PROMPT = "You have the findings of the previous research round(s). Decide whether you need MORE parallel gathering to fill specific gaps the synthesis phase can't resolve on its own.\n\nYou will receive:\n- The original user question.\n- Each prior subagent's question + FINDINGS + SOURCES block.\n\nDecision rules:\n- ONLY emit follow-ups when there is a CONCRETE gap that needs more raw evidence \u2014 a contradiction begging for a third source, a claim that needs primary-document verification, a missing data point that one round can't synthesize around.\n- The follow-up subagents WILL be given the prior findings as context in their prompt, so phrasing like \"verify the casualty figure of X reported by Iranian state media against independent sources\" is fine.\n- DO NOT emit follow-ups that just rephrase prior queries or chase tangents.\n- Each follow-up still runs in parallel with the others in this round, so follow-ups must be independent of EACH OTHER (just like round-1 queries).\n- If the prior findings are sufficient for a good synthesis, emit none and stop. The synthesis turn handles cross-cutting comparison without help.\n\nReply with EXACTLY one of these formats and nothing else:\n\nFOLLOWUPS:\n1. <follow-up gathering query>\n2. <follow-up gathering query>\n...\n\nor\n\nFOLLOWUPS: (none)\n\nStop after the last line.";
32
+ /**
33
+ * Synthesis turn: consume the per-subagent findings + sources and
34
+ * produce a single structured writeup with renumbered citations.
35
+ */
36
+ export declare const SYNTHESIS_SYSTEM_PROMPT = "You are synthesizing a deep-research report from the findings of multiple subagents \u2014 possibly across multiple research rounds (an initial gathering round plus optional follow-up rounds that drilled into specific gaps the initial round surfaced).\n\nYou will receive the original question, each subagent's question + round number + FINDINGS + SOURCES block. Produce the final writeup with these sections, in this order:\n\n## Executive summary\n<3-5 bullet points; the key takeaways.>\n\n## Key findings\n<numbered paragraphs covering each substantive finding, citing sources inline as [n] referring to the unified Sources list below. Call out contradictions explicitly. Mark gaps as \"Not covered: \u2026\". When findings from a follow-up round resolve or amplify a contradiction the initial round surfaced, say so.>\n\n## Sources\n[1] <title> \u2014 <url>\n[2] <title> \u2014 <url>\n...\n(Renumber so the unified list is contiguous; each source appears once even if cited by multiple subagents.)\n\n## Open questions\n<bullets describing what remains unresolved, or \"None \u2014 the gathered evidence is sufficient.\">\n\nBe tight. Do not narrate your process.";
37
+ /** Refuse plans larger than this in the initial round — guards against runaway fan-out cost. */
38
+ export declare const MAX_SUBAGENTS = 6;
39
+ /** Maximum follow-up rounds after the initial gathering. */
40
+ export declare const MAX_FOLLOWUP_ROUNDS = 2;
41
+ /** Maximum follow-up queries per round. */
42
+ export declare const MAX_FOLLOWUPS_PER_ROUND = 4;
43
+ export declare const MAX_REDRAFTS = 3;
44
+ export declare const SUBAGENT_MAX_ITERATIONS = 40;
45
+ /**
46
+ * Per-finding character cap when a prior round's findings are embedded as
47
+ * context into EACH follow-up subagent's prompt. The same blob is duplicated
48
+ * across every sibling subagent and re-sent every round, so an uncapped
49
+ * multi-KB finding grows the embedded context multiplicatively. The full
50
+ * untruncated text is still used for the single synthesis turn.
51
+ */
52
+ export declare const SUBAGENT_PRIOR_FINDING_MAX_CHARS = 1500;
53
+ /**
54
+ * Tools each subagent is allowed to call. Constrained to read-only web +
55
+ * filesystem reads — no edits, no shell, no git, so a runaway subagent
56
+ * can't damage the working tree. WebSearch / WebFetch may be exposed
57
+ * under different names depending on plugin configuration; the registry
58
+ * silently ignores unknown names, so listing both common spellings is
59
+ * harmless.
60
+ */
61
+ export declare const SUBAGENT_ALLOWED_TOOLS: readonly ["WebSearch", "WebFetch", "web_search", "web_fetch", "Read", "read"];
62
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAE7C,eAAO,MAAM,uBAAuB,+BAA0C,CAAC;AAE/E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,usCAgBF,CAAC;AAEpC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,6iBAYiC,CAAC;AAErE;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,2zCAwBd,CAAC;AAE3B;;;GAGG;AACH,eAAO,MAAM,uBAAuB,qpCAmBG,CAAC;AAExC,gGAAgG;AAChG,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,2CAA2C;AAC3C,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,+EAOzB,CAAC"}
@@ -0,0 +1,141 @@
1
+ import { asPluginId } from '@moxxy/sdk';
2
+ export const RESEARCH_MODE_NAME = 'research';
3
+ export const DEEP_RESEARCH_PLUGIN_ID = asPluginId('@moxxy/mode-deep-research');
4
+ /**
5
+ * Asked once in the planning phase. The subagents fan out IN PARALLEL —
6
+ * which means a query can never depend on another query's output. If we
7
+ * let the planner emit "compare side A and side B" or "what are the
8
+ * disputed claims" as separate queries, the subagent running them has
9
+ * no idea what was actually gathered and either invents content or
10
+ * gives up (e.g. "I can't determine what 'the disputed claims' refers
11
+ * to from the prompt alone"). The synthesis phase already sees every
12
+ * subagent's findings end-to-end and is where comparison + contradiction
13
+ * analysis belongs — the planner's job is purely to spread the raw
14
+ * gathering work across independent angles.
15
+ */
16
+ export const QUERY_PLAN_SYSTEM_PROMPT = `You are scoping a deep-research task. Produce 2-5 PARALLEL GATHERING queries — one per independent angle of raw evidence the synthesis phase will need.
17
+
18
+ HARD RULES (the loop refuses plans that break these):
19
+ - Each query MUST be independently answerable from web search + page reads ALONE — without seeing any other query's output. The subagents run in parallel and never see each other's findings.
20
+ - DO NOT emit comparison, contradiction, "differences", "disputed claims", "which side is right", "balanced timeline", "verify side X's claims", or other queries that require knowing what OTHER queries returned. Those are the synthesis phase's job, not gathering.
21
+ - DO NOT pad. If the user's question only needs 2 angles (e.g. "compare X side vs Y side"), emit exactly 2 queries — one per side. The synthesis turn does the comparison.
22
+ - Each query should be concrete and scoped ("What did <party> say about <topic> in the last 30 days?"), not an open theme ("Background on X").
23
+ - No two queries should be rephrasings of each other.
24
+
25
+ Reply with EXACTLY this format and nothing else:
26
+
27
+ QUERIES:
28
+ 1. <gathering query>
29
+ 2. <gathering query>
30
+ ...
31
+
32
+ Stop after the last numbered line.`;
33
+ /**
34
+ * System prompt for each fan-out subagent. They run in standard tool-use
35
+ * mode, but constrained (by allowedTools) to read-only web tools. The
36
+ * SOURCES: block is what the synthesis phase pulls citations from.
37
+ */
38
+ export const SUBAGENT_SYSTEM_PROMPT = `You are a focused research subagent. You have ONE sub-question to answer. Use web_search and web_fetch (and Read for any local files referenced) to gather evidence, then produce a concise writeup.
39
+
40
+ Stop tool-calling when you have enough material to answer. Reply with:
41
+
42
+ FINDINGS:
43
+ <2-4 short paragraphs answering the sub-question, citing sources inline like [1], [2] where claims come from a specific source>
44
+
45
+ SOURCES:
46
+ [1] <title> — <url>
47
+ [2] <title> — <url>
48
+ ...
49
+
50
+ Do NOT edit files. Do NOT run git. Stop after the last source line.`;
51
+ /**
52
+ * Asked between fan-out rounds. Given the findings from the prior
53
+ * round(s), the model decides whether MORE parallel gathering is
54
+ * needed to fill specific gaps before synthesis — and if so, what.
55
+ * This is the "agentic" half of the loop that the user explicitly
56
+ * asked for: round-1 gathers Iran-side + USA-side, round-2 spawns
57
+ * follow-ups armed with both, instead of asking blind round-1
58
+ * subagents to compare things they can't see.
59
+ */
60
+ export const FOLLOWUP_PLAN_SYSTEM_PROMPT = `You have the findings of the previous research round(s). Decide whether you need MORE parallel gathering to fill specific gaps the synthesis phase can't resolve on its own.
61
+
62
+ You will receive:
63
+ - The original user question.
64
+ - Each prior subagent's question + FINDINGS + SOURCES block.
65
+
66
+ Decision rules:
67
+ - ONLY emit follow-ups when there is a CONCRETE gap that needs more raw evidence — a contradiction begging for a third source, a claim that needs primary-document verification, a missing data point that one round can't synthesize around.
68
+ - The follow-up subagents WILL be given the prior findings as context in their prompt, so phrasing like "verify the casualty figure of X reported by Iranian state media against independent sources" is fine.
69
+ - DO NOT emit follow-ups that just rephrase prior queries or chase tangents.
70
+ - Each follow-up still runs in parallel with the others in this round, so follow-ups must be independent of EACH OTHER (just like round-1 queries).
71
+ - If the prior findings are sufficient for a good synthesis, emit none and stop. The synthesis turn handles cross-cutting comparison without help.
72
+
73
+ Reply with EXACTLY one of these formats and nothing else:
74
+
75
+ FOLLOWUPS:
76
+ 1. <follow-up gathering query>
77
+ 2. <follow-up gathering query>
78
+ ...
79
+
80
+ or
81
+
82
+ FOLLOWUPS: (none)
83
+
84
+ Stop after the last line.`;
85
+ /**
86
+ * Synthesis turn: consume the per-subagent findings + sources and
87
+ * produce a single structured writeup with renumbered citations.
88
+ */
89
+ export const SYNTHESIS_SYSTEM_PROMPT = `You are synthesizing a deep-research report from the findings of multiple subagents — possibly across multiple research rounds (an initial gathering round plus optional follow-up rounds that drilled into specific gaps the initial round surfaced).
90
+
91
+ You will receive the original question, each subagent's question + round number + FINDINGS + SOURCES block. Produce the final writeup with these sections, in this order:
92
+
93
+ ## Executive summary
94
+ <3-5 bullet points; the key takeaways.>
95
+
96
+ ## Key findings
97
+ <numbered paragraphs covering each substantive finding, citing sources inline as [n] referring to the unified Sources list below. Call out contradictions explicitly. Mark gaps as "Not covered: …". When findings from a follow-up round resolve or amplify a contradiction the initial round surfaced, say so.>
98
+
99
+ ## Sources
100
+ [1] <title> — <url>
101
+ [2] <title> — <url>
102
+ ...
103
+ (Renumber so the unified list is contiguous; each source appears once even if cited by multiple subagents.)
104
+
105
+ ## Open questions
106
+ <bullets describing what remains unresolved, or "None — the gathered evidence is sufficient.">
107
+
108
+ Be tight. Do not narrate your process.`;
109
+ /** Refuse plans larger than this in the initial round — guards against runaway fan-out cost. */
110
+ export const MAX_SUBAGENTS = 6;
111
+ /** Maximum follow-up rounds after the initial gathering. */
112
+ export const MAX_FOLLOWUP_ROUNDS = 2;
113
+ /** Maximum follow-up queries per round. */
114
+ export const MAX_FOLLOWUPS_PER_ROUND = 4;
115
+ export const MAX_REDRAFTS = 3;
116
+ export const SUBAGENT_MAX_ITERATIONS = 40;
117
+ /**
118
+ * Per-finding character cap when a prior round's findings are embedded as
119
+ * context into EACH follow-up subagent's prompt. The same blob is duplicated
120
+ * across every sibling subagent and re-sent every round, so an uncapped
121
+ * multi-KB finding grows the embedded context multiplicatively. The full
122
+ * untruncated text is still used for the single synthesis turn.
123
+ */
124
+ export const SUBAGENT_PRIOR_FINDING_MAX_CHARS = 1500;
125
+ /**
126
+ * Tools each subagent is allowed to call. Constrained to read-only web +
127
+ * filesystem reads — no edits, no shell, no git, so a runaway subagent
128
+ * can't damage the working tree. WebSearch / WebFetch may be exposed
129
+ * under different names depending on plugin configuration; the registry
130
+ * silently ignores unknown names, so listing both common spellings is
131
+ * harmless.
132
+ */
133
+ export const SUBAGENT_ALLOWED_TOOLS = [
134
+ 'WebSearch',
135
+ 'WebFetch',
136
+ 'web_search',
137
+ 'web_fetch',
138
+ 'Read',
139
+ 'read',
140
+ ];
141
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAE7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC,2BAA2B,CAAC,CAAC;AAE/E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;mCAgBL,CAAC;AAEpC;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;oEAY8B,CAAC;AAErE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;0BAwBjB,CAAC;AAE3B;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;uCAmBA,CAAC;AAExC,gGAAgG;AAChG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAE/B,4DAA4D;AAC5D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,2CAA2C;AAC3C,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAE9B,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,IAAI,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,WAAW;IACX,UAAU;IACV,YAAY;IACZ,WAAW;IACX,MAAM;IACN,MAAM;CACE,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { ModeContext, SubagentResult } from '@moxxy/sdk';
2
+ export interface FanoutOutcome {
3
+ readonly results: ReadonlyArray<SubagentResult>;
4
+ readonly errored: ReadonlyArray<{
5
+ readonly index: number;
6
+ readonly message: string;
7
+ }>;
8
+ }
9
+ /**
10
+ * Findings accumulated across rounds — each entry is one subagent's
11
+ * outcome plus the round it ran in. Synthesis and follow-up planning
12
+ * both work off this flat list.
13
+ */
14
+ export interface RoundFinding {
15
+ readonly round: number;
16
+ readonly question: string;
17
+ readonly text: string;
18
+ readonly error?: string;
19
+ }
20
+ export declare function flattenOutcome(round: number, queries: ReadonlyArray<string>, outcome: FanoutOutcome): RoundFinding[];
21
+ /**
22
+ * Spawn one subagent per query in parallel, each constrained to web /
23
+ * read-only tools. When `priorFindings` is non-empty, the prior
24
+ * findings are embedded in each subagent's user prompt so follow-up
25
+ * agents see what earlier rounds already gathered (which is the whole
26
+ * point of multi-round research — round-2 follow-ups should not be
27
+ * blind to round-1's findings).
28
+ *
29
+ * Caller MUST have verified ctx.subagents is present.
30
+ */
31
+ export declare function runFanout(ctx: ModeContext, queries: ReadonlyArray<string>, priorFindings?: ReadonlyArray<RoundFinding>): Promise<FanoutOutcome>;
32
+ /**
33
+ * Build a one-screen digest of subagent outcomes for the synthesis gate.
34
+ * Each entry shows the sub-question and a 200-char headline of the
35
+ * findings, plus a clear marker for any subagent that errored.
36
+ */
37
+ export declare function buildFanoutDigest(findings: ReadonlyArray<RoundFinding>): string;
38
+ /**
39
+ * Build the synthesis turn's user message: weaves the original question
40
+ * back together with each subagent's writeup so the synthesizer has the
41
+ * raw material to cite and combine.
42
+ */
43
+ export declare function buildSynthesisInput(originalPrompt: string, findings: ReadonlyArray<RoundFinding>): string;
44
+ //# sourceMappingURL=fanout-phase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fanout-phase.d.ts","sourceRoot":"","sources":["../src/fanout-phase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAgB,MAAM,YAAY,CAAC;AAS5E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IAChD,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvF;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE,aAAa,GACrB,YAAY,EAAE,CAWhB;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,aAAa,GAAE,aAAa,CAAC,YAAY,CAAM,GAC9C,OAAO,CAAC,aAAa,CAAC,CAoCxB;AAqCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,MAAM,CAgB/E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GACpC,MAAM,CAeR"}
@@ -0,0 +1,133 @@
1
+ import { SUBAGENT_ALLOWED_TOOLS, SUBAGENT_MAX_ITERATIONS, SUBAGENT_PRIOR_FINDING_MAX_CHARS, SUBAGENT_SYSTEM_PROMPT, } from './constants.js';
2
+ export function flattenOutcome(round, queries, outcome) {
3
+ return queries.map((question, i) => {
4
+ const r = outcome.results[i];
5
+ const err = outcome.errored.find((e) => e.index === i);
6
+ return {
7
+ round,
8
+ question,
9
+ text: (r?.text ?? '').trim(),
10
+ ...(err ? { error: err.message } : {}),
11
+ };
12
+ });
13
+ }
14
+ /**
15
+ * Spawn one subagent per query in parallel, each constrained to web /
16
+ * read-only tools. When `priorFindings` is non-empty, the prior
17
+ * findings are embedded in each subagent's user prompt so follow-up
18
+ * agents see what earlier rounds already gathered (which is the whole
19
+ * point of multi-round research — round-2 follow-ups should not be
20
+ * blind to round-1's findings).
21
+ *
22
+ * Caller MUST have verified ctx.subagents is present.
23
+ */
24
+ export async function runFanout(ctx, queries, priorFindings = []) {
25
+ if (!ctx.subagents) {
26
+ throw new Error('deep-research: runFanout called without ctx.subagents — caller bug');
27
+ }
28
+ const specs = queries.map((q, i) => ({
29
+ prompt: buildSubagentPrompt(q, priorFindings),
30
+ systemPrompt: SUBAGENT_SYSTEM_PROMPT,
31
+ mode: 'default',
32
+ maxIterations: SUBAGENT_MAX_ITERATIONS,
33
+ allowedTools: [...SUBAGENT_ALLOWED_TOOLS],
34
+ label: `subagent-${i + 1}`,
35
+ }));
36
+ let results;
37
+ try {
38
+ results = await ctx.subagents.spawnAll(specs);
39
+ }
40
+ catch (err) {
41
+ // spawnAll is Promise.all under the hood (run-child.ts) — a single child's
42
+ // setup work (strategy/model resolution, log appends, tool-registry build)
43
+ // throwing OUTSIDE its own try/catch rejects the whole batch. Treat that as
44
+ // every-subagent-errored rather than letting the rejection crash the entire
45
+ // research turn and discard all prior-round findings. flattenOutcome turns
46
+ // these into RoundFinding rows the loop carries into synthesis.
47
+ const message = err instanceof Error ? err.message : String(err);
48
+ return {
49
+ results: [],
50
+ errored: queries.map((_, index) => ({ index, message })),
51
+ };
52
+ }
53
+ const errored = [];
54
+ results.forEach((r, i) => {
55
+ if (r.error)
56
+ errored.push({ index: i, message: r.error.message });
57
+ });
58
+ return { results, errored };
59
+ }
60
+ function buildSubagentPrompt(query, priorFindings) {
61
+ if (priorFindings.length === 0)
62
+ return query;
63
+ const sections = [];
64
+ sections.push('Earlier research rounds gathered the following findings — use them as context for the focused question at the bottom, but you still need to do your own search to answer the focused question.');
65
+ sections.push('');
66
+ for (const f of priorFindings) {
67
+ sections.push(`### Round ${f.round}: ${f.question}`);
68
+ if (f.error) {
69
+ sections.push(`(errored: ${f.error})`);
70
+ }
71
+ else {
72
+ // Cap each embedded finding: the SAME prior-findings blob is duplicated
73
+ // into every sibling subagent's prompt every round, so unbounded text
74
+ // grows multiplicatively and can blow the subagent's context window. The
75
+ // full untruncated text is preserved only for the single synthesis turn.
76
+ sections.push(capFindingText(f.text) || '(empty response)');
77
+ }
78
+ sections.push('');
79
+ }
80
+ sections.push('---');
81
+ sections.push('');
82
+ sections.push(`Your focused follow-up question:\n${query}`);
83
+ return sections.join('\n');
84
+ }
85
+ /** Bound a prior finding's text before it is embedded into a subagent prompt. */
86
+ function capFindingText(text) {
87
+ if (text.length <= SUBAGENT_PRIOR_FINDING_MAX_CHARS)
88
+ return text;
89
+ return `${text.slice(0, SUBAGENT_PRIOR_FINDING_MAX_CHARS)}\n…[truncated]`;
90
+ }
91
+ /**
92
+ * Build a one-screen digest of subagent outcomes for the synthesis gate.
93
+ * Each entry shows the sub-question and a 200-char headline of the
94
+ * findings, plus a clear marker for any subagent that errored.
95
+ */
96
+ export function buildFanoutDigest(findings) {
97
+ const total = findings.length;
98
+ const errored = findings.filter((f) => f.error).length;
99
+ const ok = total - errored;
100
+ const head = `${ok} of ${total} subagent${total === 1 ? '' : 's'} returned`;
101
+ const errStub = errored > 0 ? `, ${errored} errored` : '';
102
+ const blocks = findings.map((f, i) => {
103
+ if (f.error) {
104
+ return `${i + 1}. [round ${f.round}] ${f.question}\n [errored: ${f.error}]`;
105
+ }
106
+ const headline = f.text.trim().slice(0, 200).replace(/\n+/g, ' ');
107
+ return `${i + 1}. [round ${f.round}] ${f.question}\n ${headline || '(empty response)'}`;
108
+ });
109
+ return `${head}${errStub}.\n\n${blocks.join('\n\n')}`;
110
+ }
111
+ /**
112
+ * Build the synthesis turn's user message: weaves the original question
113
+ * back together with each subagent's writeup so the synthesizer has the
114
+ * raw material to cite and combine.
115
+ */
116
+ export function buildSynthesisInput(originalPrompt, findings) {
117
+ const parts = [];
118
+ parts.push(`Original question:\n${originalPrompt}`);
119
+ parts.push('');
120
+ parts.push('Sub-question findings:');
121
+ findings.forEach((f, i) => {
122
+ parts.push('');
123
+ parts.push(`### #${i + 1} (round ${f.round}): ${f.question}`);
124
+ if (f.error) {
125
+ parts.push(`(errored: ${f.error})`);
126
+ }
127
+ else {
128
+ parts.push(f.text || '(empty response)');
129
+ }
130
+ });
131
+ return parts.join('\n');
132
+ }
133
+ //# sourceMappingURL=fanout-phase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fanout-phase.js","sourceRoot":"","sources":["../src/fanout-phase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { RESEARCH_MODE_NAME } from './constants.js';
2
+ export { parseFollowups, parseQueries } from './parse-queries.js';
3
+ export { buildFanoutDigest, buildSynthesisInput, flattenOutcome, type RoundFinding, } from './fanout-phase.js';
4
+ export declare const deepResearchMode: import("@moxxy/sdk").ModeDef;
5
+ export declare const deepResearchModePlugin: import("@moxxy/sdk").Plugin;
6
+ export default deepResearchModePlugin;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,gBAAgB,8BAI3B,CAAC;AAEH,eAAO,MAAM,sBAAsB,6BAIjC,CAAC;AAEH,eAAe,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ import { defineMode, definePlugin } from '@moxxy/sdk';
2
+ import { RESEARCH_MODE_NAME } from './constants.js';
3
+ import { runDeepResearchMode } from './research-loop.js';
4
+ export { RESEARCH_MODE_NAME } from './constants.js';
5
+ export { parseFollowups, parseQueries } from './parse-queries.js';
6
+ export { buildFanoutDigest, buildSynthesisInput, flattenOutcome, } from './fanout-phase.js';
7
+ export const deepResearchMode = defineMode({
8
+ name: RESEARCH_MODE_NAME,
9
+ description: 'Fan-out research: plan queries, run subagents in parallel, synthesise a report',
10
+ run: runDeepResearchMode,
11
+ });
12
+ export const deepResearchModePlugin = definePlugin({
13
+ name: '@moxxy/mode-deep-research',
14
+ version: '0.0.0',
15
+ modes: [deepResearchMode],
16
+ });
17
+ export default deepResearchModePlugin;
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,GAEf,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;IACzC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,gFAAgF;IAC7F,GAAG,EAAE,mBAAmB;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;IACjD,IAAI,EAAE,2BAA2B;IACjC,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,CAAC,gBAAgB,CAAC;CAC1B,CAAC,CAAC;AAEH,eAAe,sBAAsB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Parse the planner's output into individual sub-question strings — a
3
+ * numbered list under a QUERIES: header.
4
+ */
5
+ export declare function parseQueries(text: string): string[];
6
+ /**
7
+ * Parse the follow-up planner output. Accepts either a numbered list
8
+ * under `FOLLOWUPS:` OR the literal `FOLLOWUPS: (none)` form. Returns
9
+ * an empty array in both the "(none)" and "no parseable items" cases —
10
+ * the loop treats both as "no more research needed, proceed to synthesis".
11
+ */
12
+ export declare function parseFollowups(text: string): string[];
13
+ //# sourceMappingURL=parse-queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-queries.d.ts","sourceRoot":"","sources":["../src/parse-queries.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CASrD"}