@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.
- package/LICENSE +21 -0
- package/dist/approval.d.ts +32 -0
- package/dist/approval.d.ts.map +1 -0
- package/dist/approval.js +84 -0
- package/dist/approval.js.map +1 -0
- package/dist/constants.d.ts +62 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +141 -0
- package/dist/constants.js.map +1 -0
- package/dist/fanout-phase.d.ts +44 -0
- package/dist/fanout-phase.d.ts.map +1 -0
- package/dist/fanout-phase.js +133 -0
- package/dist/fanout-phase.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/parse-queries.d.ts +13 -0
- package/dist/parse-queries.d.ts.map +1 -0
- package/dist/parse-queries.js +71 -0
- package/dist/parse-queries.js.map +1 -0
- package/dist/query-phase.d.ts +15 -0
- package/dist/query-phase.d.ts.map +1 -0
- package/dist/query-phase.js +81 -0
- package/dist/query-phase.js.map +1 -0
- package/dist/research-loop.d.ts +18 -0
- package/dist/research-loop.d.ts.map +1 -0
- package/dist/research-loop.js +357 -0
- package/dist/research-loop.js.map +1 -0
- package/dist/synthesis-phase.d.ts +8 -0
- package/dist/synthesis-phase.d.ts.map +1 -0
- package/dist/synthesis-phase.js +21 -0
- package/dist/synthesis-phase.js.map +1 -0
- package/package.json +73 -0
- package/src/approval.test.ts +82 -0
- package/src/approval.ts +105 -0
- package/src/constants.ts +153 -0
- package/src/fanout-phase.ts +177 -0
- package/src/index.test.ts +575 -0
- package/src/index.ts +27 -0
- package/src/parse-queries.ts +72 -0
- package/src/query-phase.ts +123 -0
- package/src/research-loop.ts +414 -0
- package/src/synthesis-phase.ts +25 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the planner's output into individual sub-question strings — a
|
|
3
|
+
* numbered list under a QUERIES: header.
|
|
4
|
+
*/
|
|
5
|
+
export function parseQueries(text) {
|
|
6
|
+
return parseNumberedBlock(text, /^queries\s*:?$/i);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse the follow-up planner output. Accepts either a numbered list
|
|
10
|
+
* under `FOLLOWUPS:` OR the literal `FOLLOWUPS: (none)` form. Returns
|
|
11
|
+
* an empty array in both the "(none)" and "no parseable items" cases —
|
|
12
|
+
* the loop treats both as "no more research needed, proceed to synthesis".
|
|
13
|
+
*/
|
|
14
|
+
export function parseFollowups(text) {
|
|
15
|
+
const items = parseNumberedBlock(text, /^followups\s*:?$/i);
|
|
16
|
+
// "(none)" sentinel — the model is telling us no follow-ups are needed.
|
|
17
|
+
// Anchor it to a full line so a parenthetical that merely follows the
|
|
18
|
+
// header (e.g. "FOLLOWUPS:\n(none of the prior sources covered cost)\n1. …")
|
|
19
|
+
// doesn't swallow a genuine numbered list below it. Only honor the sentinel
|
|
20
|
+
// when no numbered items were parsed.
|
|
21
|
+
if (items.length === 0 && /^followups\s*:\s*\(none\)\s*$/im.test(text))
|
|
22
|
+
return [];
|
|
23
|
+
return items;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Cap on a single joined query/follow-up. A hostile or malformed model could
|
|
27
|
+
* emit thousands of continuation lines that all attach to one item; bound the
|
|
28
|
+
* per-item growth so a mangled plan can't produce a multi-MB subagent prompt.
|
|
29
|
+
*/
|
|
30
|
+
const MAX_ITEM_CHARS = 2000;
|
|
31
|
+
function parseNumberedBlock(text, headerRegex) {
|
|
32
|
+
const lines = text.split('\n');
|
|
33
|
+
const items = [];
|
|
34
|
+
// Tracks whether the previous meaningful line was (or extended) a list item,
|
|
35
|
+
// so we only ever join wrapped continuations onto a real item.
|
|
36
|
+
let continuationOpen = false;
|
|
37
|
+
for (const raw of lines) {
|
|
38
|
+
const line = raw.trim();
|
|
39
|
+
// A blank line ends the current item's continuation run: a wrapped query
|
|
40
|
+
// never spans a blank line, so this prevents an unrelated trailing
|
|
41
|
+
// paragraph from being glued onto the last query.
|
|
42
|
+
if (!line) {
|
|
43
|
+
continuationOpen = false;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (headerRegex.test(line)) {
|
|
47
|
+
// A header also closes any open continuation run.
|
|
48
|
+
continuationOpen = false;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const m = /^(?:\d+[.)]|[-*•])\s*(.+)$/.exec(line);
|
|
52
|
+
if (m) {
|
|
53
|
+
items.push(m[1].trim());
|
|
54
|
+
continuationOpen = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// Non-list line. If it directly continues an open item (the model wrapped a
|
|
58
|
+
// long query across lines), join it on rather than silently truncating the
|
|
59
|
+
// query — a dropped continuation gets sent to a subagent as a half-question.
|
|
60
|
+
// A non-list line with NO open item (junk preamble, a "(none …)" header
|
|
61
|
+
// parenthetical, etc.) is still dropped.
|
|
62
|
+
if (continuationOpen && items.length > 0) {
|
|
63
|
+
const last = items[items.length - 1];
|
|
64
|
+
const joined = `${last} ${line}`;
|
|
65
|
+
items[items.length - 1] =
|
|
66
|
+
joined.length > MAX_ITEM_CHARS ? joined.slice(0, MAX_ITEM_CHARS) : joined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return items;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=parse-queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-queries.js","sourceRoot":"","sources":["../src/parse-queries.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;IAC5D,wEAAwE;IACxE,sEAAsE;IACtE,6EAA6E;IAC7E,4EAA4E;IAC5E,sCAAsC;IACtC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,iCAAiC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAClF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,SAAS,kBAAkB,CAAC,IAAY,EAAE,WAAmB;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,6EAA6E;IAC7E,+DAA+D;IAC/D,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,yEAAyE;QACzE,mEAAmE;QACnE,kDAAkD;QAClD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,gBAAgB,GAAG,KAAK,CAAC;YACzB,SAAS;QACX,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,kDAAkD;YAClD,gBAAgB,GAAG,KAAK,CAAC;YACzB,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,CAAC,EAAE,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACzB,gBAAgB,GAAG,IAAI,CAAC;YACxB,SAAS;QACX,CAAC;QACD,4EAA4E;QAC5E,2EAA2E;QAC3E,6EAA6E;QAC7E,wEAAwE;QACxE,yCAAyC;QACzC,IAAI,gBAAgB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;YACtC,MAAM,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;YACjC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;gBACrB,MAAM,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ModeContext } from '@moxxy/sdk';
|
|
2
|
+
import type { RoundFinding } from './fanout-phase.js';
|
|
3
|
+
/**
|
|
4
|
+
* Drive the initial query-planning turn. Single-shot stream — the
|
|
5
|
+
* planner shouldn't be web-searching, that's the subagents' job.
|
|
6
|
+
* Returns the raw text, or null on provider error (already emitted).
|
|
7
|
+
*/
|
|
8
|
+
export declare function collectQueryPlan(ctx: ModeContext, redraftFeedback: string | null): Promise<string | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Drive the follow-up planning turn between gather rounds. The model
|
|
11
|
+
* sees the prior round(s)' findings as context and decides whether to
|
|
12
|
+
* spawn more parallel research or move to synthesis.
|
|
13
|
+
*/
|
|
14
|
+
export declare function collectFollowupPlan(ctx: ModeContext, originalPrompt: string, priorFindings: ReadonlyArray<RoundFinding>): Promise<string | null>;
|
|
15
|
+
//# sourceMappingURL=query-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-phase.d.ts","sourceRoot":"","sources":["../src/query-phase.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAMpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,MAAM,GAAG,IAAI,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,WAAW,EAChB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,aAAa,CAAC,YAAY,CAAC,GACzC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { buildSystemPromptWithSkills, runSingleShotTurn, } from '@moxxy/sdk';
|
|
2
|
+
import { FOLLOWUP_PLAN_SYSTEM_PROMPT, QUERY_PLAN_SYSTEM_PROMPT, } from './constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Drive the initial query-planning turn. Single-shot stream — the
|
|
5
|
+
* planner shouldn't be web-searching, that's the subagents' job.
|
|
6
|
+
* Returns the raw text, or null on provider error (already emitted).
|
|
7
|
+
*/
|
|
8
|
+
export async function collectQueryPlan(ctx, redraftFeedback) {
|
|
9
|
+
const messages = buildPlannerMessages(ctx, QUERY_PLAN_SYSTEM_PROMPT, buildInitialUserMessages(ctx, redraftFeedback));
|
|
10
|
+
return runSingleShotTurn(ctx, messages, { maxTokens: 800 });
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Drive the follow-up planning turn between gather rounds. The model
|
|
14
|
+
* sees the prior round(s)' findings as context and decides whether to
|
|
15
|
+
* spawn more parallel research or move to synthesis.
|
|
16
|
+
*/
|
|
17
|
+
export async function collectFollowupPlan(ctx, originalPrompt, priorFindings) {
|
|
18
|
+
const messages = buildPlannerMessages(ctx, FOLLOWUP_PLAN_SYSTEM_PROMPT, buildFollowupUserMessages(originalPrompt, priorFindings));
|
|
19
|
+
return runSingleShotTurn(ctx, messages, { maxTokens: 800 });
|
|
20
|
+
}
|
|
21
|
+
function buildPlannerMessages(ctx, systemPrompt, userMessages) {
|
|
22
|
+
const systemWithSkills = buildSystemPromptWithSkills(ctx.systemPrompt, ctx.skills.list()) ?? '';
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
role: 'system',
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: 'text',
|
|
29
|
+
text: systemPrompt + (systemWithSkills ? `\n\n${systemWithSkills}` : ''),
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
...userMessages,
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
function buildInitialUserMessages(ctx, redraftFeedback) {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const e of ctx.log.slice()) {
|
|
39
|
+
if (e.type === 'user_prompt') {
|
|
40
|
+
out.push({ role: 'user', content: [{ type: 'text', text: e.text }] });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (redraftFeedback) {
|
|
44
|
+
out.push({
|
|
45
|
+
role: 'user',
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: 'text',
|
|
49
|
+
text: `The previous query plan needs to be redrafted. Feedback from the user: ${redraftFeedback}\n\n` +
|
|
50
|
+
`Produce a new QUERIES block addressing this feedback.`,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function buildFollowupUserMessages(originalPrompt, priorFindings) {
|
|
58
|
+
const sections = [];
|
|
59
|
+
sections.push(`Original question:\n${originalPrompt}`);
|
|
60
|
+
sections.push('');
|
|
61
|
+
sections.push('Prior research findings:');
|
|
62
|
+
for (const f of priorFindings) {
|
|
63
|
+
sections.push('');
|
|
64
|
+
sections.push(`### Round ${f.round}, sub-question: ${f.question}`);
|
|
65
|
+
if (f.error) {
|
|
66
|
+
sections.push(`(errored: ${f.error})`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
sections.push(f.text.trim() || '(empty response)');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
sections.push('');
|
|
73
|
+
sections.push('Decide whether more parallel research is needed. Reply with a FOLLOWUPS: block as instructed.');
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
role: 'user',
|
|
77
|
+
content: [{ type: 'text', text: sections.join('\n') }],
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=query-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-phase.js","sourceRoot":"","sources":["../src/query-phase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ModeContext, MoxxyEvent } from '@moxxy/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Deep-research loop:
|
|
4
|
+
* 1. Plan QUERIES: block (with redraft-able approval gate)
|
|
5
|
+
* 2. Fan out (round 1) — one subagent per gathering query, in parallel
|
|
6
|
+
* 3. Up to MAX_FOLLOWUP_ROUNDS of:
|
|
7
|
+
* a. Ask model "given findings so far, do you need follow-ups?"
|
|
8
|
+
* b. If yes, fan out follow-ups with the prior findings as
|
|
9
|
+
* context in each subagent's prompt.
|
|
10
|
+
* c. If no, break out.
|
|
11
|
+
* 4. Synthesis approval gate (digest of all rounds)
|
|
12
|
+
* 5. Synthesize the final cited writeup.
|
|
13
|
+
*
|
|
14
|
+
* Headless contexts auto-approve both gates. Missing ctx.subagents is
|
|
15
|
+
* fatal — fan-out is the whole point of this mode.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runDeepResearchMode(ctx: ModeContext): AsyncIterable<MoxxyEvent>;
|
|
18
|
+
//# sourceMappingURL=research-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"research-loop.d.ts","sourceRoot":"","sources":["../src/research-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAyB1D;;;;;;;;;;;;;;GAcG;AACH,wBAAuB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC,CA8HtF"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { runQueryApprovalGate, runSynthesisApprovalGate, } from './approval.js';
|
|
2
|
+
import { RESEARCH_MODE_NAME, DEEP_RESEARCH_PLUGIN_ID, MAX_FOLLOWUPS_PER_ROUND, MAX_FOLLOWUP_ROUNDS, MAX_REDRAFTS, MAX_SUBAGENTS, } from './constants.js';
|
|
3
|
+
import { buildFanoutDigest, buildSynthesisInput, flattenOutcome, runFanout, } from './fanout-phase.js';
|
|
4
|
+
import { parseFollowups, parseQueries } from './parse-queries.js';
|
|
5
|
+
import { collectFollowupPlan, collectQueryPlan } from './query-phase.js';
|
|
6
|
+
import { collectSynthesis } from './synthesis-phase.js';
|
|
7
|
+
/**
|
|
8
|
+
* Deep-research loop:
|
|
9
|
+
* 1. Plan QUERIES: block (with redraft-able approval gate)
|
|
10
|
+
* 2. Fan out (round 1) — one subagent per gathering query, in parallel
|
|
11
|
+
* 3. Up to MAX_FOLLOWUP_ROUNDS of:
|
|
12
|
+
* a. Ask model "given findings so far, do you need follow-ups?"
|
|
13
|
+
* b. If yes, fan out follow-ups with the prior findings as
|
|
14
|
+
* context in each subagent's prompt.
|
|
15
|
+
* c. If no, break out.
|
|
16
|
+
* 4. Synthesis approval gate (digest of all rounds)
|
|
17
|
+
* 5. Synthesize the final cited writeup.
|
|
18
|
+
*
|
|
19
|
+
* Headless contexts auto-approve both gates. Missing ctx.subagents is
|
|
20
|
+
* fatal — fan-out is the whole point of this mode.
|
|
21
|
+
*/
|
|
22
|
+
export async function* runDeepResearchMode(ctx) {
|
|
23
|
+
if (ctx.signal.aborted) {
|
|
24
|
+
yield await ctx.emit({
|
|
25
|
+
type: 'abort',
|
|
26
|
+
sessionId: ctx.sessionId,
|
|
27
|
+
turnId: ctx.turnId,
|
|
28
|
+
source: 'system',
|
|
29
|
+
reason: 'aborted before deep-research start',
|
|
30
|
+
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!ctx.subagents) {
|
|
34
|
+
yield await ctx.emit({
|
|
35
|
+
type: 'error',
|
|
36
|
+
sessionId: ctx.sessionId,
|
|
37
|
+
turnId: ctx.turnId,
|
|
38
|
+
source: 'system',
|
|
39
|
+
kind: 'fatal',
|
|
40
|
+
message: 'research: ctx.subagents is unavailable (the @moxxy/plugin-subagents plugin appears disabled). ' +
|
|
41
|
+
'Re-enable it, or switch to the default mode for a serial alternative.',
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
yield await ctx.emit({
|
|
46
|
+
type: 'mode_iteration',
|
|
47
|
+
sessionId: ctx.sessionId,
|
|
48
|
+
turnId: ctx.turnId,
|
|
49
|
+
source: 'system',
|
|
50
|
+
strategy: RESEARCH_MODE_NAME,
|
|
51
|
+
iteration: 0,
|
|
52
|
+
routing: 'unresolved',
|
|
53
|
+
});
|
|
54
|
+
// Phase 1: query plan (with redraftable gate).
|
|
55
|
+
const planning = yield* runPlanningPhase(ctx);
|
|
56
|
+
if (planning === null)
|
|
57
|
+
return;
|
|
58
|
+
const { queries, originalPrompt } = planning;
|
|
59
|
+
// Phase 2: round-1 fan out.
|
|
60
|
+
const allFindings = [];
|
|
61
|
+
const round1 = yield* runRound(ctx, 1, queries, []);
|
|
62
|
+
if (round1 === null)
|
|
63
|
+
return;
|
|
64
|
+
allFindings.push(...round1);
|
|
65
|
+
// Phase 3: follow-up rounds, capped to MAX_FOLLOWUP_ROUNDS.
|
|
66
|
+
for (let round = 2; round <= MAX_FOLLOWUP_ROUNDS + 1; round += 1) {
|
|
67
|
+
if (ctx.signal.aborted)
|
|
68
|
+
return;
|
|
69
|
+
const followups = yield* runFollowupPlan(ctx, originalPrompt, allFindings, round);
|
|
70
|
+
if (followups === null)
|
|
71
|
+
return;
|
|
72
|
+
if (followups.length === 0) {
|
|
73
|
+
yield await ctx.emit({
|
|
74
|
+
type: 'plugin_event',
|
|
75
|
+
sessionId: ctx.sessionId,
|
|
76
|
+
turnId: ctx.turnId,
|
|
77
|
+
source: 'plugin',
|
|
78
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
79
|
+
subtype: 'deep_research_followups_none',
|
|
80
|
+
payload: { round },
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
const nextRound = yield* runRound(ctx, round, followups, allFindings);
|
|
85
|
+
if (nextRound === null)
|
|
86
|
+
return;
|
|
87
|
+
allFindings.push(...nextRound);
|
|
88
|
+
}
|
|
89
|
+
if (ctx.signal.aborted)
|
|
90
|
+
return;
|
|
91
|
+
// Phase 4: synthesis approval gate.
|
|
92
|
+
const digest = buildFanoutDigest(allFindings);
|
|
93
|
+
const gate = await runSynthesisApprovalGate(ctx, digest);
|
|
94
|
+
if (gate.kind === 'cancel') {
|
|
95
|
+
yield await ctx.emit({
|
|
96
|
+
type: 'abort',
|
|
97
|
+
sessionId: ctx.sessionId,
|
|
98
|
+
turnId: ctx.turnId,
|
|
99
|
+
source: 'user',
|
|
100
|
+
reason: 'synthesis cancelled by user',
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Phase 5: synthesize.
|
|
105
|
+
const synthesisInput = buildSynthesisInput(originalPrompt, allFindings);
|
|
106
|
+
const synthesisText = await collectSynthesis(ctx, synthesisInput);
|
|
107
|
+
if (synthesisText === null)
|
|
108
|
+
return;
|
|
109
|
+
// Synthesis is a multi-second provider call; if the user aborted while it ran,
|
|
110
|
+
// emit an abort rather than the finished report — matching the abort discipline
|
|
111
|
+
// every other phase in this loop follows (see the ctx.signal.aborted guards above).
|
|
112
|
+
if (ctx.signal.aborted) {
|
|
113
|
+
yield await ctx.emit({
|
|
114
|
+
type: 'abort',
|
|
115
|
+
sessionId: ctx.sessionId,
|
|
116
|
+
turnId: ctx.turnId,
|
|
117
|
+
source: 'system',
|
|
118
|
+
reason: 'aborted during synthesis',
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
yield await ctx.emit({
|
|
123
|
+
type: 'assistant_message',
|
|
124
|
+
sessionId: ctx.sessionId,
|
|
125
|
+
turnId: ctx.turnId,
|
|
126
|
+
source: 'model',
|
|
127
|
+
content: synthesisText,
|
|
128
|
+
stopReason: 'end_turn',
|
|
129
|
+
});
|
|
130
|
+
yield await ctx.emit({
|
|
131
|
+
type: 'plugin_event',
|
|
132
|
+
sessionId: ctx.sessionId,
|
|
133
|
+
turnId: ctx.turnId,
|
|
134
|
+
source: 'plugin',
|
|
135
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
136
|
+
subtype: 'deep_research_synthesis_completed',
|
|
137
|
+
payload: {
|
|
138
|
+
totalFindings: allFindings.length,
|
|
139
|
+
rounds: Math.max(...allFindings.map((f) => f.round), 1),
|
|
140
|
+
errored: allFindings.filter((f) => f.error).length,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* One round of parallel fan-out — emits start/complete events around
|
|
146
|
+
* runFanout. Returns the per-round findings, or null on abort.
|
|
147
|
+
*/
|
|
148
|
+
async function* runRound(ctx, round, queries, priorFindings) {
|
|
149
|
+
yield await ctx.emit({
|
|
150
|
+
type: 'plugin_event',
|
|
151
|
+
sessionId: ctx.sessionId,
|
|
152
|
+
turnId: ctx.turnId,
|
|
153
|
+
source: 'plugin',
|
|
154
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
155
|
+
subtype: 'deep_research_fanout_started',
|
|
156
|
+
payload: { round, queries: queries.length },
|
|
157
|
+
});
|
|
158
|
+
const outcome = await runFanout(ctx, queries, priorFindings);
|
|
159
|
+
yield await ctx.emit({
|
|
160
|
+
type: 'plugin_event',
|
|
161
|
+
sessionId: ctx.sessionId,
|
|
162
|
+
turnId: ctx.turnId,
|
|
163
|
+
source: 'plugin',
|
|
164
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
165
|
+
subtype: 'deep_research_fanout_completed',
|
|
166
|
+
payload: {
|
|
167
|
+
round,
|
|
168
|
+
total: queries.length,
|
|
169
|
+
errored: outcome.errored.length,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
if (ctx.signal.aborted)
|
|
173
|
+
return null;
|
|
174
|
+
return flattenOutcome(round, queries, outcome);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Ask the model whether to fan out more queries, given everything
|
|
178
|
+
* gathered so far. Returns the parsed follow-up queries (may be empty)
|
|
179
|
+
* or null on a fatal error.
|
|
180
|
+
*/
|
|
181
|
+
async function* runFollowupPlan(ctx, originalPrompt, priorFindings, round) {
|
|
182
|
+
yield await ctx.emit({
|
|
183
|
+
type: 'plugin_event',
|
|
184
|
+
sessionId: ctx.sessionId,
|
|
185
|
+
turnId: ctx.turnId,
|
|
186
|
+
source: 'plugin',
|
|
187
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
188
|
+
subtype: 'deep_research_followups_planning',
|
|
189
|
+
payload: { round, basedOn: priorFindings.length },
|
|
190
|
+
});
|
|
191
|
+
const text = await collectFollowupPlan(ctx, originalPrompt, priorFindings);
|
|
192
|
+
if (text === null)
|
|
193
|
+
return null;
|
|
194
|
+
const followups = parseFollowups(text);
|
|
195
|
+
// Apply cap and surface the trim as an event — but only when there's
|
|
196
|
+
// something to draft. The empty case is signalled by the caller via
|
|
197
|
+
// `deep_research_followups_none`; emitting a "drafted with kept=0"
|
|
198
|
+
// event here would be a duplicate "nothing to do" signal.
|
|
199
|
+
const trimmed = followups.slice(0, MAX_FOLLOWUPS_PER_ROUND);
|
|
200
|
+
if (trimmed.length === 0)
|
|
201
|
+
return [];
|
|
202
|
+
yield await ctx.emit({
|
|
203
|
+
type: 'plugin_event',
|
|
204
|
+
sessionId: ctx.sessionId,
|
|
205
|
+
turnId: ctx.turnId,
|
|
206
|
+
source: 'plugin',
|
|
207
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
208
|
+
subtype: 'deep_research_followups_drafted',
|
|
209
|
+
payload: {
|
|
210
|
+
round,
|
|
211
|
+
proposed: followups.length,
|
|
212
|
+
kept: trimmed.length,
|
|
213
|
+
queries: trimmed,
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
// Materialize the follow-up plan as an assistant_message so the user
|
|
217
|
+
// sees the queries that are about to run, even without an approval
|
|
218
|
+
// gate. (We deliberately skip a per-round approval gate to keep the
|
|
219
|
+
// user-facing checkpoints lightweight — the synthesis gate at the
|
|
220
|
+
// end is the final go/no-go.)
|
|
221
|
+
yield await ctx.emit({
|
|
222
|
+
type: 'assistant_message',
|
|
223
|
+
sessionId: ctx.sessionId,
|
|
224
|
+
turnId: ctx.turnId,
|
|
225
|
+
source: 'model',
|
|
226
|
+
content: `Follow-up round ${round} — spawning ${trimmed.length} more subagent${trimmed.length === 1 ? '' : 's'}:\n` +
|
|
227
|
+
trimmed.map((q, i) => `${i + 1}. ${q}`).join('\n'),
|
|
228
|
+
stopReason: 'end_turn',
|
|
229
|
+
});
|
|
230
|
+
return trimmed;
|
|
231
|
+
}
|
|
232
|
+
async function* runPlanningPhase(ctx) {
|
|
233
|
+
// Capture the original prompt from the log so we can re-include it in
|
|
234
|
+
// synthesis context. Use the LAST user_prompt — the one that triggered this
|
|
235
|
+
// turn — to stay consistent with how the runner scopes a turn (a multi-turn
|
|
236
|
+
// session's earlier prompts would otherwise anchor synthesis on a stale
|
|
237
|
+
// question). null = no user prompt at all (empty log).
|
|
238
|
+
const originalPrompt = (() => {
|
|
239
|
+
const events = ctx.log.slice();
|
|
240
|
+
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
241
|
+
const e = events[i];
|
|
242
|
+
if (e.type === 'user_prompt')
|
|
243
|
+
return e.text;
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
})();
|
|
247
|
+
if (originalPrompt === null) {
|
|
248
|
+
yield await ctx.emit({
|
|
249
|
+
type: 'error',
|
|
250
|
+
sessionId: ctx.sessionId,
|
|
251
|
+
turnId: ctx.turnId,
|
|
252
|
+
source: 'system',
|
|
253
|
+
kind: 'fatal',
|
|
254
|
+
message: 'deep-research: no user prompt found in the session log — nothing to research.',
|
|
255
|
+
});
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
let redraftFeedback = null;
|
|
259
|
+
let redraftCount = 0;
|
|
260
|
+
while (true) {
|
|
261
|
+
if (ctx.signal.aborted) {
|
|
262
|
+
yield await ctx.emit({
|
|
263
|
+
type: 'abort',
|
|
264
|
+
sessionId: ctx.sessionId,
|
|
265
|
+
turnId: ctx.turnId,
|
|
266
|
+
source: 'system',
|
|
267
|
+
reason: 'aborted during planning',
|
|
268
|
+
});
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const planText = await collectQueryPlan(ctx, redraftFeedback);
|
|
272
|
+
if (planText === null)
|
|
273
|
+
return null;
|
|
274
|
+
const queries = parseQueries(planText);
|
|
275
|
+
yield await ctx.emit({
|
|
276
|
+
type: 'plugin_event',
|
|
277
|
+
sessionId: ctx.sessionId,
|
|
278
|
+
turnId: ctx.turnId,
|
|
279
|
+
source: 'plugin',
|
|
280
|
+
pluginId: DEEP_RESEARCH_PLUGIN_ID,
|
|
281
|
+
subtype: 'deep_research_queries_drafted',
|
|
282
|
+
payload: { text: planText, queries, redraft: redraftCount },
|
|
283
|
+
});
|
|
284
|
+
if (queries.length === 0) {
|
|
285
|
+
yield await ctx.emit({
|
|
286
|
+
type: 'assistant_message',
|
|
287
|
+
sessionId: ctx.sessionId,
|
|
288
|
+
turnId: ctx.turnId,
|
|
289
|
+
source: 'model',
|
|
290
|
+
content: planText,
|
|
291
|
+
stopReason: 'end_turn',
|
|
292
|
+
});
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
if (queries.length > MAX_SUBAGENTS) {
|
|
296
|
+
// Over-production is a normal, recoverable failure mode ("be exhaustive"
|
|
297
|
+
// prompts trip it easily). When an interactive resolver is present and we
|
|
298
|
+
// still have redraft budget, auto-redraft asking the planner to narrow,
|
|
299
|
+
// rather than killing the whole turn. Headless (no approval) or once the
|
|
300
|
+
// redraft cap is exhausted, fall through to the fatal abort.
|
|
301
|
+
const nextCount = redraftCount + 1;
|
|
302
|
+
if (ctx.approval && nextCount <= MAX_REDRAFTS) {
|
|
303
|
+
redraftCount = nextCount;
|
|
304
|
+
redraftFeedback =
|
|
305
|
+
`You produced ${queries.length} queries; the cap is ${MAX_SUBAGENTS}. ` +
|
|
306
|
+
`Return at most ${MAX_SUBAGENTS} parallel gathering queries.`;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
yield await ctx.emit({
|
|
310
|
+
type: 'error',
|
|
311
|
+
sessionId: ctx.sessionId,
|
|
312
|
+
turnId: ctx.turnId,
|
|
313
|
+
source: 'system',
|
|
314
|
+
kind: 'fatal',
|
|
315
|
+
message: `deep-research: refusing a ${queries.length}-query plan (cap is ${MAX_SUBAGENTS}). Narrow scope or rephrase.`,
|
|
316
|
+
});
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
const gate = await runQueryApprovalGate(ctx, planText, queries.length, redraftCount);
|
|
320
|
+
redraftCount = gate.redraftCount;
|
|
321
|
+
if (gate.outcome.kind === 'cancel') {
|
|
322
|
+
yield await ctx.emit({
|
|
323
|
+
type: 'abort',
|
|
324
|
+
sessionId: ctx.sessionId,
|
|
325
|
+
turnId: ctx.turnId,
|
|
326
|
+
source: 'user',
|
|
327
|
+
reason: 'query plan rejected by user',
|
|
328
|
+
});
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
if (gate.outcome.kind === 'redraft-cap-exceeded') {
|
|
332
|
+
yield await ctx.emit({
|
|
333
|
+
type: 'error',
|
|
334
|
+
sessionId: ctx.sessionId,
|
|
335
|
+
turnId: ctx.turnId,
|
|
336
|
+
source: 'system',
|
|
337
|
+
kind: 'fatal',
|
|
338
|
+
message: `deep-research: redrafted ${MAX_REDRAFTS}× without approval; aborting.`,
|
|
339
|
+
});
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
if (gate.outcome.kind === 'redraft') {
|
|
343
|
+
redraftFeedback = gate.outcome.feedback;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
yield await ctx.emit({
|
|
347
|
+
type: 'assistant_message',
|
|
348
|
+
sessionId: ctx.sessionId,
|
|
349
|
+
turnId: ctx.turnId,
|
|
350
|
+
source: 'model',
|
|
351
|
+
content: planText,
|
|
352
|
+
stopReason: 'end_turn',
|
|
353
|
+
});
|
|
354
|
+
return { queries, originalPrompt };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=research-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"research-loop.js","sourceRoot":"","sources":["../src/research-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ModeContext } from '@moxxy/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Run the synthesis turn: single-shot stream that consumes the
|
|
4
|
+
* per-subagent findings and produces the final structured writeup.
|
|
5
|
+
* Returns the assembled text or null on error.
|
|
6
|
+
*/
|
|
7
|
+
export declare function collectSynthesis(ctx: ModeContext, inputBody: string): Promise<string | null>;
|
|
8
|
+
//# sourceMappingURL=synthesis-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesis-phase.d.ts","sourceRoot":"","sources":["../src/synthesis-phase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAwB,MAAM,YAAY,CAAC;AAIvF;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { runSingleShotTurn } from '@moxxy/sdk';
|
|
2
|
+
import { SYNTHESIS_SYSTEM_PROMPT } from './constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Run the synthesis turn: single-shot stream that consumes the
|
|
5
|
+
* per-subagent findings and produces the final structured writeup.
|
|
6
|
+
* Returns the assembled text or null on error.
|
|
7
|
+
*/
|
|
8
|
+
export async function collectSynthesis(ctx, inputBody) {
|
|
9
|
+
const messages = [
|
|
10
|
+
{
|
|
11
|
+
role: 'system',
|
|
12
|
+
content: [{ type: 'text', text: SYNTHESIS_SYSTEM_PROMPT }],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
role: 'user',
|
|
16
|
+
content: [{ type: 'text', text: inputBody }],
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
return runSingleShotTurn(ctx, messages, { maxTokens: 4096 });
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=synthesis-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesis-phase.js","sourceRoot":"","sources":["../src/synthesis-phase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0C,MAAM,YAAY,CAAC;AAEvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAgB,EAChB,SAAiB;IAEjB,MAAM,QAAQ,GAAsB;QAClC;YACE,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;SAC3D;QACD;YACE,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SAC7C;KACF,CAAC;IACF,OAAO,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC"}
|