@mcp-abap-adt/llm-agent-libs 16.2.0 → 17.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/adapters/llm-provider-bridge.js +2 -2
- package/dist/adapters/llm-provider-bridge.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +48 -37
- package/dist/agent.js.map +1 -1
- package/dist/builder.d.ts +10 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +17 -3
- package/dist/builder.js.map +1 -1
- package/dist/classifier/llm-classifier.d.ts.map +1 -1
- package/dist/classifier/llm-classifier.js +1 -0
- package/dist/classifier/llm-classifier.js.map +1 -1
- package/dist/coordinator/dag/abort-error-strategy.d.ts +7 -0
- package/dist/coordinator/dag/abort-error-strategy.d.ts.map +1 -0
- package/dist/coordinator/dag/abort-error-strategy.js +8 -0
- package/dist/coordinator/dag/abort-error-strategy.js.map +1 -0
- package/dist/coordinator/dag/compose-node-task.d.ts +8 -0
- package/dist/coordinator/dag/compose-node-task.d.ts.map +1 -0
- package/dist/coordinator/dag/compose-node-task.js +41 -0
- package/dist/coordinator/dag/compose-node-task.js.map +1 -0
- package/dist/coordinator/dag/dag-plan-interpreter.d.ts +9 -0
- package/dist/coordinator/dag/dag-plan-interpreter.d.ts.map +1 -0
- package/dist/coordinator/dag/dag-plan-interpreter.js +220 -0
- package/dist/coordinator/dag/dag-plan-interpreter.js.map +1 -0
- package/dist/coordinator/dag/index.d.ts +5 -0
- package/dist/coordinator/dag/index.d.ts.map +1 -0
- package/dist/coordinator/dag/index.js +5 -0
- package/dist/coordinator/dag/index.js.map +1 -0
- package/dist/coordinator/dag/llm-dag-planner.d.ts +17 -0
- package/dist/coordinator/dag/llm-dag-planner.d.ts.map +1 -0
- package/dist/coordinator/dag/llm-dag-planner.js +152 -0
- package/dist/coordinator/dag/llm-dag-planner.js.map +1 -0
- package/dist/coordinator/dag/llm-finalizer.d.ts +21 -0
- package/dist/coordinator/dag/llm-finalizer.d.ts.map +1 -0
- package/dist/coordinator/dag/llm-finalizer.js +77 -0
- package/dist/coordinator/dag/llm-finalizer.js.map +1 -0
- package/dist/coordinator/dag/llm-review-strategy.d.ts +17 -0
- package/dist/coordinator/dag/llm-review-strategy.d.ts.map +1 -0
- package/dist/coordinator/dag/llm-review-strategy.js +149 -0
- package/dist/coordinator/dag/llm-review-strategy.js.map +1 -0
- package/dist/coordinator/dag/noop-review-strategy.d.ts +8 -0
- package/dist/coordinator/dag/noop-review-strategy.d.ts.map +1 -0
- package/dist/coordinator/dag/noop-review-strategy.js +11 -0
- package/dist/coordinator/dag/noop-review-strategy.js.map +1 -0
- package/dist/coordinator/dag/passthrough-finalizer.d.ts +11 -0
- package/dist/coordinator/dag/passthrough-finalizer.d.ts.map +1 -0
- package/dist/coordinator/dag/passthrough-finalizer.js +13 -0
- package/dist/coordinator/dag/passthrough-finalizer.js.map +1 -0
- package/dist/coordinator/dag/render-ancestor-context.d.ts +8 -0
- package/dist/coordinator/dag/render-ancestor-context.d.ts.map +1 -0
- package/dist/coordinator/dag/render-ancestor-context.js +27 -0
- package/dist/coordinator/dag/render-ancestor-context.js.map +1 -0
- package/dist/coordinator/dag/replan-error-strategy.d.ts +15 -0
- package/dist/coordinator/dag/replan-error-strategy.d.ts.map +1 -0
- package/dist/coordinator/dag/replan-error-strategy.js +32 -0
- package/dist/coordinator/dag/replan-error-strategy.js.map +1 -0
- package/dist/coordinator/dag/reviewer-error-strategy.d.ts +15 -0
- package/dist/coordinator/dag/reviewer-error-strategy.d.ts.map +1 -0
- package/dist/coordinator/dag/reviewer-error-strategy.js +38 -0
- package/dist/coordinator/dag/reviewer-error-strategy.js.map +1 -0
- package/dist/coordinator/dag/splice-sub-plan.d.ts +12 -0
- package/dist/coordinator/dag/splice-sub-plan.d.ts.map +1 -0
- package/dist/coordinator/dag/splice-sub-plan.js +41 -0
- package/dist/coordinator/dag/splice-sub-plan.js.map +1 -0
- package/dist/coordinator/dag/subagent-state-oracle.d.ts +19 -0
- package/dist/coordinator/dag/subagent-state-oracle.d.ts.map +1 -0
- package/dist/coordinator/dag/subagent-state-oracle.js +31 -0
- package/dist/coordinator/dag/subagent-state-oracle.js.map +1 -0
- package/dist/coordinator/dag/template-finalizer.d.ts +11 -0
- package/dist/coordinator/dag/template-finalizer.d.ts.map +1 -0
- package/dist/coordinator/dag/template-finalizer.js +17 -0
- package/dist/coordinator/dag/template-finalizer.js.map +1 -0
- package/dist/coordinator/dispatch/subagent.d.ts.map +1 -1
- package/dist/coordinator/dispatch/subagent.js +6 -12
- package/dist/coordinator/dispatch/subagent.js.map +1 -1
- package/dist/coordinator/index.d.ts +6 -0
- package/dist/coordinator/index.d.ts.map +1 -1
- package/dist/coordinator/index.js +6 -0
- package/dist/coordinator/index.js.map +1 -1
- package/dist/coordinator/planning/one-shot.d.ts.map +1 -1
- package/dist/coordinator/planning/one-shot.js +14 -7
- package/dist/coordinator/planning/one-shot.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/logger/default-request-logger.d.ts +18 -6
- package/dist/logger/default-request-logger.d.ts.map +1 -1
- package/dist/logger/default-request-logger.js +15 -4
- package/dist/logger/default-request-logger.js.map +1 -1
- package/dist/logger/noop-request-logger.d.ts +10 -5
- package/dist/logger/noop-request-logger.d.ts.map +1 -1
- package/dist/logger/noop-request-logger.js +4 -3
- package/dist/logger/noop-request-logger.js.map +1 -1
- package/dist/logger/session-request-logger.d.ts +50 -0
- package/dist/logger/session-request-logger.d.ts.map +1 -0
- package/dist/logger/session-request-logger.js +151 -0
- package/dist/logger/session-request-logger.js.map +1 -0
- package/dist/pipeline/context.d.ts +8 -3
- package/dist/pipeline/context.d.ts.map +1 -1
- package/dist/pipeline/default-pipeline.d.ts +27 -4
- package/dist/pipeline/default-pipeline.d.ts.map +1 -1
- package/dist/pipeline/default-pipeline.js +42 -7
- package/dist/pipeline/default-pipeline.js.map +1 -1
- package/dist/pipeline/handlers/coordinator.d.ts +0 -3
- package/dist/pipeline/handlers/coordinator.d.ts.map +1 -1
- package/dist/pipeline/handlers/coordinator.js +33 -22
- package/dist/pipeline/handlers/coordinator.js.map +1 -1
- package/dist/pipeline/handlers/dag-coordinator.d.ts +47 -0
- package/dist/pipeline/handlers/dag-coordinator.d.ts.map +1 -0
- package/dist/pipeline/handlers/dag-coordinator.js +369 -0
- package/dist/pipeline/handlers/dag-coordinator.js.map +1 -0
- package/dist/pipeline/handlers/index.d.ts +7 -0
- package/dist/pipeline/handlers/index.d.ts.map +1 -1
- package/dist/pipeline/handlers/index.js +5 -1
- package/dist/pipeline/handlers/index.js.map +1 -1
- package/dist/pipeline/handlers/rag-query.d.ts.map +1 -1
- package/dist/pipeline/handlers/rag-query.js +1 -0
- package/dist/pipeline/handlers/rag-query.js.map +1 -1
- package/dist/pipeline/handlers/subagent.d.ts.map +1 -1
- package/dist/pipeline/handlers/subagent.js +0 -2
- package/dist/pipeline/handlers/subagent.js.map +1 -1
- package/dist/pipeline/handlers/summarize.d.ts.map +1 -1
- package/dist/pipeline/handlers/summarize.js +5 -0
- package/dist/pipeline/handlers/summarize.js.map +1 -1
- package/dist/pipeline/handlers/tool-loop.d.ts.map +1 -1
- package/dist/pipeline/handlers/tool-loop.js +16 -0
- package/dist/pipeline/handlers/tool-loop.js.map +1 -1
- package/dist/pipeline/handlers/translate.d.ts.map +1 -1
- package/dist/pipeline/handlers/translate.js +1 -0
- package/dist/pipeline/handlers/translate.js.map +1 -1
- package/dist/pipeline/index.d.ts +2 -1
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +1 -1
- package/dist/pipeline/index.js.map +1 -1
- package/dist/session/session-graph-factory.d.ts +66 -0
- package/dist/session/session-graph-factory.d.ts.map +1 -0
- package/dist/session/session-graph-factory.js +63 -0
- package/dist/session/session-graph-factory.js.map +1 -0
- package/dist/session/session-graph.d.ts +54 -0
- package/dist/session/session-graph.d.ts.map +1 -0
- package/dist/session/session-graph.js +76 -0
- package/dist/session/session-graph.js.map +1 -0
- package/dist/session/session-registry.d.ts +89 -0
- package/dist/session/session-registry.d.ts.map +1 -0
- package/dist/session/session-registry.js +279 -0
- package/dist/session/session-registry.js.map +1 -0
- package/dist/subagent/direct-llm-subagent.d.ts.map +1 -1
- package/dist/subagent/direct-llm-subagent.js +0 -2
- package/dist/subagent/direct-llm-subagent.js.map +1 -1
- package/dist/subagent/smart-agent-subagent.d.ts.map +1 -1
- package/dist/subagent/smart-agent-subagent.js +3 -3
- package/dist/subagent/smart-agent-subagent.js.map +1 -1
- package/package.json +14 -14
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ClarifySignal, NeedInfoSignal } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
import { DirectLlmSubAgent } from '../../subagent/direct-llm-subagent.js';
|
|
3
|
+
import { renderAncestorContext } from './render-ancestor-context.js';
|
|
4
|
+
/**
|
|
5
|
+
* Attach LLM usage to a thrown Error so the coordinator's runRole catch can
|
|
6
|
+
* still bill the spend (HIGH/MEDIUM finding: parse-/shape-error paths went
|
|
7
|
+
* through `throw new Error(...)` and the captured `res.usage` was lost — yet
|
|
8
|
+
* the LLM call WAS made and tokens WERE spent). Plain Errors with a `usage`
|
|
9
|
+
* property work in JS without subclassing; runRole reads it via a type cast.
|
|
10
|
+
*/
|
|
11
|
+
function withUsage(err, usage) {
|
|
12
|
+
if (usage)
|
|
13
|
+
err.usage = usage;
|
|
14
|
+
return err;
|
|
15
|
+
}
|
|
16
|
+
// Static planner instructions. The agent catalog and user prompt are NOT here —
|
|
17
|
+
// they are dynamic and go into the per-call `task` (see plan()).
|
|
18
|
+
export const PLANNER_SYSTEM = `You are a planner. Decompose the user request into a DAG of tasks.
|
|
19
|
+
Each node: {"id","goal","agent"(optional worker name),"dependsOn"(optional ids),"needsInput"(optional bool)}.
|
|
20
|
+
Use "dependsOn" to express order/data-flow; independent nodes run in parallel.
|
|
21
|
+
|
|
22
|
+
DECOMPOSITION COST. Each node spawns a fresh worker pipeline. Workers
|
|
23
|
+
DO NOT share fetched data, tools, or context across nodes — every node
|
|
24
|
+
pays the full classify + RAG + tool-loop overhead again, and any
|
|
25
|
+
source / configuration / table data already fetched by a previous
|
|
26
|
+
node will be re-fetched. Over-decomposition is the most common cause
|
|
27
|
+
of large token bills. Decompose ONLY when:
|
|
28
|
+
- nodes target DIFFERENT objects (e.g. compare program A vs program B),
|
|
29
|
+
- nodes can TRULY run in parallel for wall-clock speedup, or
|
|
30
|
+
- a later node depends on a fact ONLY discoverable by an earlier node.
|
|
31
|
+
|
|
32
|
+
For analysing a SINGLE object along multiple dimensions (e.g. "review
|
|
33
|
+
program X for security, performance, clean-core, maintainability") use
|
|
34
|
+
ONE node — the worker covers every dimension in one tool-loop.
|
|
35
|
+
|
|
36
|
+
Emit a plan-level "objective". Respond with ONLY one of:
|
|
37
|
+
{"objective":"...","nodes":[{"id":"n1","goal":"...","agent":"<worker name or omit>","dependsOn":[],"needsInput":false}]}
|
|
38
|
+
{"needInfo":"<query>"} — if you need a reality fact before planning (e.g. which table exists)
|
|
39
|
+
{"clarify":"<question>"} — if you need a human decision before planning (e.g. overwrite ok?)`;
|
|
40
|
+
/**
|
|
41
|
+
* Role adapter: owns a constrained `DirectLlmSubAgent` and turns its string
|
|
42
|
+
* output into a typed `DagPlan`. (Slice 2: planner now flows through the one
|
|
43
|
+
* ISubAgent path instead of calling ILlm directly.)
|
|
44
|
+
*/
|
|
45
|
+
export class LlmDagPlanner {
|
|
46
|
+
name = 'llm-dag';
|
|
47
|
+
/** Best-effort model identifier from the underlying ILlm (for logger
|
|
48
|
+
* attribution). May be undefined for ILlm impls that do not expose one. */
|
|
49
|
+
model;
|
|
50
|
+
agent;
|
|
51
|
+
constructor(llm) {
|
|
52
|
+
this.model = llm.model;
|
|
53
|
+
this.agent = new DirectLlmSubAgent('planner', llm, {
|
|
54
|
+
systemPrompt: PLANNER_SYSTEM,
|
|
55
|
+
contextPolicy: 'optional',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async plan(input) {
|
|
59
|
+
const catalog = input.agents
|
|
60
|
+
.map((a) => `- ${a.name}: ${a.description ?? '(no description)'}`)
|
|
61
|
+
.join('\n');
|
|
62
|
+
const contextPrefix = [];
|
|
63
|
+
if (input.ancestorContext) {
|
|
64
|
+
const rendered = renderAncestorContext(input.ancestorContext);
|
|
65
|
+
if (rendered)
|
|
66
|
+
contextPrefix.push(rendered);
|
|
67
|
+
}
|
|
68
|
+
if (input.reviewerFeedback) {
|
|
69
|
+
contextPrefix.push(`Reviewer feedback: ${input.reviewerFeedback}`);
|
|
70
|
+
}
|
|
71
|
+
const prefix = contextPrefix.length > 0 ? `${contextPrefix.join('\n\n')}\n\n` : '';
|
|
72
|
+
const task = `${prefix}Available workers:\n${catalog || '(none)'}\n\n${input.prompt}`;
|
|
73
|
+
const res = await this.agent.run({
|
|
74
|
+
task,
|
|
75
|
+
sessionId: input.sessionId,
|
|
76
|
+
signal: input.signal,
|
|
77
|
+
});
|
|
78
|
+
const content = res.output;
|
|
79
|
+
const match = content.match(/\{[\s\S]*\}/);
|
|
80
|
+
if (!match)
|
|
81
|
+
throw withUsage(new Error(`Planner output did not contain a JSON object: ${content.slice(0, 200)}`), res.usage);
|
|
82
|
+
// Field values come straight from untrusted JSON, so they are typed as
|
|
83
|
+
// `unknown` and validated below before being narrowed to PlanNode.
|
|
84
|
+
let parsed;
|
|
85
|
+
try {
|
|
86
|
+
parsed = JSON.parse(match[0]);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
throw withUsage(new Error(`Planner output contained malformed JSON: ${match[0].slice(0, 200)}`), res.usage);
|
|
90
|
+
}
|
|
91
|
+
if (typeof parsed.needInfo === 'string' && parsed.needInfo.trim()) {
|
|
92
|
+
// Forward LLM usage on the signal path so the coordinator can attribute
|
|
93
|
+
// planner spend even when the role short-circuits with a signal (HIGH
|
|
94
|
+
// finding: signal paths previously discarded the captured `res.usage`).
|
|
95
|
+
throw new NeedInfoSignal(parsed.needInfo, res.usage);
|
|
96
|
+
}
|
|
97
|
+
if (typeof parsed.clarify === 'string' && parsed.clarify.trim()) {
|
|
98
|
+
throw new ClarifySignal(parsed.clarify, res.usage);
|
|
99
|
+
}
|
|
100
|
+
if (!Array.isArray(parsed.nodes) || parsed.nodes.length === 0) {
|
|
101
|
+
throw withUsage(new Error(`Planner returned no nodes: ${match[0].slice(0, 200)}`), res.usage);
|
|
102
|
+
}
|
|
103
|
+
if (parsed.objective !== undefined &&
|
|
104
|
+
typeof parsed.objective !== 'string') {
|
|
105
|
+
throw withUsage(new Error(`Planner objective must be a string: ${JSON.stringify(parsed.objective)}`), res.usage);
|
|
106
|
+
}
|
|
107
|
+
if (parsed.rationale !== undefined &&
|
|
108
|
+
typeof parsed.rationale !== 'string') {
|
|
109
|
+
throw withUsage(new Error(`Planner rationale must be a string: ${JSON.stringify(parsed.rationale)}`), res.usage);
|
|
110
|
+
}
|
|
111
|
+
const nodes = parsed.nodes.map((n, i) => {
|
|
112
|
+
if (typeof n.goal !== 'string' || n.goal.trim() === '') {
|
|
113
|
+
throw withUsage(new Error(`Planner node is missing a goal: ${JSON.stringify(n)}`), res.usage);
|
|
114
|
+
}
|
|
115
|
+
if (n.id !== undefined && typeof n.id !== 'string') {
|
|
116
|
+
throw withUsage(new Error(`Planner node has a non-string id: ${JSON.stringify(n)}`), res.usage);
|
|
117
|
+
}
|
|
118
|
+
if (n.agent !== undefined && typeof n.agent !== 'string') {
|
|
119
|
+
throw withUsage(new Error(`Planner node has a non-string agent: ${JSON.stringify(n)}`), res.usage);
|
|
120
|
+
}
|
|
121
|
+
if (n.dependsOn !== undefined &&
|
|
122
|
+
(!Array.isArray(n.dependsOn) ||
|
|
123
|
+
n.dependsOn.some((d) => typeof d !== 'string'))) {
|
|
124
|
+
throw withUsage(new Error(`Planner node dependsOn must be an array of strings: ${JSON.stringify(n)}`), res.usage);
|
|
125
|
+
}
|
|
126
|
+
if (n.needsInput !== undefined && typeof n.needsInput !== 'boolean') {
|
|
127
|
+
throw withUsage(new Error(`Planner node needsInput must be a boolean: ${JSON.stringify(n)}`), res.usage);
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
id: n.id ?? `n${i + 1}`,
|
|
131
|
+
goal: n.goal,
|
|
132
|
+
agent: n.agent,
|
|
133
|
+
dependsOn: n.dependsOn,
|
|
134
|
+
needsInput: n.needsInput,
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
plan: {
|
|
139
|
+
nodes,
|
|
140
|
+
objective: parsed.objective,
|
|
141
|
+
rationale: parsed.rationale,
|
|
142
|
+
createdAt: Date.now(),
|
|
143
|
+
},
|
|
144
|
+
// Forward the underlying ILlm.chat usage on the WRAPPER (not on the
|
|
145
|
+
// plan itself) so the coordinator can attribute planner-LLM spend to
|
|
146
|
+
// the session/request logger without polluting the plan domain type
|
|
147
|
+
// (which the reviewer serializes via JSON.stringify into its prompt).
|
|
148
|
+
usage: res.usage,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=llm-dag-planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-dag-planner.js","sourceRoot":"","sources":["../../../src/coordinator/dag/llm-dag-planner.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,GAAU,EAAE,KAA2B;IACxD,IAAI,KAAK;QAAG,GAAoC,CAAC,KAAK,GAAG,KAAK,CAAC;IAC/D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,iEAAiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;8FAqBgE,CAAC;AAE/F;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,SAAS,CAAC;IAC1B;gFAC4E;IACnE,KAAK,CAAU;IACP,KAAK,CAAoB;IAE1C,YAAY,GAAS;QACnB,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,IAAI,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE;YACjD,YAAY,EAAE,cAAc;YAC5B,aAAa,EAAE,UAAU;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAmB;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM;aACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAC;aACjE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAC9D,IAAI,QAAQ;gBAAE,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;YAC3B,aAAa,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,MAAM,GACV,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,GAAG,MAAM,uBAAuB,OAAO,IAAI,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QAEtF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;YAC/B,IAAI;YACJ,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;QAE3B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YACR,MAAM,SAAS,CACb,IAAI,KAAK,CACP,iDAAiD,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CACzE,EACD,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,uEAAuE;QACvE,mEAAmE;QACnE,IAAI,MAYH,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,SAAS,CACb,IAAI,KAAK,CACP,4CAA4C,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CACrE,EACD,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAClE,wEAAwE;YACxE,sEAAsE;YACtE,wEAAwE;YACxE,MAAM,IAAI,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAChE,MAAM,IAAI,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,SAAS,CACb,IAAI,KAAK,CAAC,8BAA8B,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,EACjE,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,IACE,MAAM,CAAC,SAAS,KAAK,SAAS;YAC9B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EACpC,CAAC;YACD,MAAM,SAAS,CACb,IAAI,KAAK,CACP,uCAAuC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAC1E,EACD,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,IACE,MAAM,CAAC,SAAS,KAAK,SAAS;YAC9B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EACpC,CAAC;YACD,MAAM,SAAS,CACb,IAAI,KAAK,CACP,uCAAuC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAC1E,EACD,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAe,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAClD,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBACvD,MAAM,SAAS,CACb,IAAI,KAAK,CAAC,mCAAmC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EACjE,GAAG,CAAC,KAAK,CACV,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;gBACnD,MAAM,SAAS,CACb,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EACnE,GAAG,CAAC,KAAK,CACV,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACzD,MAAM,SAAS,CACb,IAAI,KAAK,CACP,wCAAwC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAC5D,EACD,GAAG,CAAC,KAAK,CACV,CAAC;YACJ,CAAC;YACD,IACE,CAAC,CAAC,SAAS,KAAK,SAAS;gBACzB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;oBAC1B,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,EACjD,CAAC;gBACD,MAAM,SAAS,CACb,IAAI,KAAK,CACP,uDAAuD,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAC3E,EACD,GAAG,CAAC,KAAK,CACV,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACpE,MAAM,SAAS,CACb,IAAI,KAAK,CACP,8CAA8C,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAClE,EACD,GAAG,CAAC,KAAK,CACV,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,EAAE,EAAG,CAAC,CAAC,EAAyB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE;gBAC/C,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,KAAK,EAAE,CAAC,CAAC,KAA2B;gBACpC,SAAS,EAAE,CAAC,CAAC,SAAiC;gBAC9C,UAAU,EAAE,CAAC,CAAC,UAAiC;aAChD,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,OAAO;YACL,IAAI,EAAE;gBACJ,KAAK;gBACL,SAAS,EAAE,MAAM,CAAC,SAA+B;gBACjD,SAAS,EAAE,MAAM,CAAC,SAA+B;gBACjD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB;YACD,oEAAoE;YACpE,qEAAqE;YACrE,oEAAoE;YACpE,sEAAsE;YACtE,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FinalizerInput, FinalizerResult, IFinalizer, ILlm } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
export declare const FINALIZER_SYSTEM: string;
|
|
3
|
+
export interface LlmFinalizerOptions {
|
|
4
|
+
systemPrompt?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
model?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Synthesizes the final answer via a single LLM call. NO tools are wired:
|
|
10
|
+
* the LLM cannot escape into another tool-loop. The user message is a
|
|
11
|
+
* deterministic rendering of prompt + objective + ancestorContext + trace.
|
|
12
|
+
*/
|
|
13
|
+
export declare class LlmFinalizer implements IFinalizer {
|
|
14
|
+
private readonly llm;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly model?: string;
|
|
17
|
+
private readonly systemPrompt;
|
|
18
|
+
constructor(llm: ILlm, opts?: LlmFinalizerOptions);
|
|
19
|
+
finalize(input: FinalizerInput): Promise<FinalizerResult>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=llm-finalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-finalizer.d.ts","sourceRoot":"","sources":["../../../src/coordinator/dag/llm-finalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,UAAU,EACV,IAAI,EAGL,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,gBAAgB,QAM6C,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAkCD;;;;GAIG;AACH,qBAAa,YAAa,YAAW,UAAU;IAM3C,OAAO,CAAC,QAAQ,CAAC,GAAG;IALtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAGnB,GAAG,EAAE,IAAI,EAC1B,IAAI,GAAE,mBAAwB;IAO1B,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAqBhE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const FINALIZER_SYSTEM = 'You synthesize the final user-facing answer for a DAG-coordinated task. ' +
|
|
2
|
+
'You will receive: (1) the user prompt, (2) the plan objective, (3) an ' +
|
|
3
|
+
'ordered execution trace of completed DAG nodes (each with its goal and ' +
|
|
4
|
+
'output). Produce the answer using ONLY the trace outputs. Do NOT propose ' +
|
|
5
|
+
'new data collection. Do NOT include the trace structure in your reply ' +
|
|
6
|
+
"unless the user asked for it. Address every part of the user's prompt.";
|
|
7
|
+
function renderUserMessage(input) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push('# User prompt', input.prompt, '');
|
|
10
|
+
lines.push('# Plan objective', input.objective, '');
|
|
11
|
+
if (input.ancestorContext) {
|
|
12
|
+
const ac = input.ancestorContext;
|
|
13
|
+
if (ac.clarifications.length > 0) {
|
|
14
|
+
lines.push('# Clarifications');
|
|
15
|
+
for (const c of ac.clarifications) {
|
|
16
|
+
lines.push(`- Q: ${c.question}`);
|
|
17
|
+
lines.push(` A: ${c.answer}`);
|
|
18
|
+
}
|
|
19
|
+
lines.push('');
|
|
20
|
+
}
|
|
21
|
+
if (ac.oracleObservations.length > 0) {
|
|
22
|
+
lines.push('# Oracle observations');
|
|
23
|
+
for (const o of ac.oracleObservations) {
|
|
24
|
+
lines.push(`- Q: ${o.query}`);
|
|
25
|
+
lines.push(` A: ${o.answer}`);
|
|
26
|
+
}
|
|
27
|
+
lines.push('');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
lines.push('# Execution trace');
|
|
31
|
+
for (const t of input.executionTrace) {
|
|
32
|
+
lines.push(`## Node ${t.nodeId} — ${t.goal}`);
|
|
33
|
+
lines.push(t.output);
|
|
34
|
+
lines.push('');
|
|
35
|
+
}
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Synthesizes the final answer via a single LLM call. NO tools are wired:
|
|
40
|
+
* the LLM cannot escape into another tool-loop. The user message is a
|
|
41
|
+
* deterministic rendering of prompt + objective + ancestorContext + trace.
|
|
42
|
+
*/
|
|
43
|
+
export class LlmFinalizer {
|
|
44
|
+
llm;
|
|
45
|
+
name;
|
|
46
|
+
model;
|
|
47
|
+
systemPrompt;
|
|
48
|
+
constructor(llm, opts = {}) {
|
|
49
|
+
this.llm = llm;
|
|
50
|
+
this.name = opts.name ?? 'llm-finalizer';
|
|
51
|
+
this.model = opts.model;
|
|
52
|
+
this.systemPrompt = opts.systemPrompt ?? FINALIZER_SYSTEM;
|
|
53
|
+
}
|
|
54
|
+
async finalize(input) {
|
|
55
|
+
const messages = [
|
|
56
|
+
{ role: 'system', content: this.systemPrompt },
|
|
57
|
+
{ role: 'user', content: renderUserMessage(input) },
|
|
58
|
+
];
|
|
59
|
+
const { signal, sessionId } = input;
|
|
60
|
+
let buf = '';
|
|
61
|
+
let usage;
|
|
62
|
+
const stream = this.llm.streamChat(messages, [], { signal, sessionId });
|
|
63
|
+
for await (const chunk of stream) {
|
|
64
|
+
if (chunk.ok === false)
|
|
65
|
+
throw new Error(chunk.error?.message ?? 'streamChat failed');
|
|
66
|
+
const content = chunk.value?.content ?? '';
|
|
67
|
+
if (content) {
|
|
68
|
+
buf += content;
|
|
69
|
+
input.onPartial?.({ kind: 'content', delta: content });
|
|
70
|
+
}
|
|
71
|
+
if (chunk.value?.usage)
|
|
72
|
+
usage = chunk.value.usage;
|
|
73
|
+
}
|
|
74
|
+
return { output: buf, usage };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=llm-finalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-finalizer.js","sourceRoot":"","sources":["../../../src/coordinator/dag/llm-finalizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ExecutionFailureInput, ExecutionReviewResult, ILlm, IReviewStrategy, ReviewInput, ReviewResult } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Role adapter: owns a constrained `DirectLlmSubAgent` critic and turns its
|
|
4
|
+
* string output into a typed `ReviewVerdict`.
|
|
5
|
+
*/
|
|
6
|
+
export declare class LlmReviewStrategy implements IReviewStrategy {
|
|
7
|
+
readonly name = "llm-review";
|
|
8
|
+
/** Best-effort model identifier from the underlying ILlm (for logger
|
|
9
|
+
* attribution). May be undefined for ILlm impls that do not expose one. */
|
|
10
|
+
readonly model?: string;
|
|
11
|
+
private readonly agent;
|
|
12
|
+
private readonly executionAgent;
|
|
13
|
+
constructor(llm: ILlm);
|
|
14
|
+
review(input: ReviewInput): Promise<ReviewResult>;
|
|
15
|
+
reviewExecutionFailure(input: ExecutionFailureInput): Promise<ExecutionReviewResult>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=llm-review-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-review-strategy.d.ts","sourceRoot":"","sources":["../../../src/coordinator/dag/llm-review-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,qBAAqB,EACrB,qBAAqB,EACrB,IAAI,EACJ,eAAe,EAEf,WAAW,EACX,YAAY,EACb,MAAM,yBAAyB,CAAC;AA+BjC;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,eAAe;IACvD,QAAQ,CAAC,IAAI,gBAAgB;IAC7B;gFAC4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoB;gBAEvC,GAAG,EAAE,IAAI;IAYf,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA6EjD,sBAAsB,CAC1B,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;CAuFlC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { ClarifySignal, NeedInfoSignal } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
import { DirectLlmSubAgent } from '../../subagent/direct-llm-subagent.js';
|
|
3
|
+
import { renderAncestorContext } from './render-ancestor-context.js';
|
|
4
|
+
/**
|
|
5
|
+
* Attach LLM usage to a thrown Error so the coordinator's runRole catch can
|
|
6
|
+
* still bill the spend. Same rationale as the planner-side helper.
|
|
7
|
+
*/
|
|
8
|
+
function withUsage(err, usage) {
|
|
9
|
+
if (usage)
|
|
10
|
+
err.usage = usage;
|
|
11
|
+
return err;
|
|
12
|
+
}
|
|
13
|
+
// Static critic instructions. The user prompt, plan and catalog are dynamic and
|
|
14
|
+
// go into the per-call `task` (see review()).
|
|
15
|
+
const REVIEWER_SYSTEM = `You are a plan reviewer. Given the user request, the available workers, and a proposed DAG plan, decide whether the plan can fulfil the request with those workers.
|
|
16
|
+
Respond with ONLY a JSON object:
|
|
17
|
+
{"pass": true} — the plan is adequate
|
|
18
|
+
{"pass": false, "feedback": "<what is wrong or what must be clarified>"} — otherwise
|
|
19
|
+
{"needInfo":"<query>"} — if you need a reality fact to assess the plan (e.g. does table X exist?)
|
|
20
|
+
{"clarify":"<question>"} — if you need a human decision before reviewing (e.g. overwrite ok?)`;
|
|
21
|
+
const EXECUTION_REVIEW_SYSTEM = `You are a recovery reviewer. A step of a DAG plan FAILED during execution. You are given the objective, the current plan, the execution trace (what already ran and its output — this reflects the CURRENT system state), the failed step id, and the error.
|
|
22
|
+
Decide recovery and respond with ONLY a JSON object:
|
|
23
|
+
{"action":"abort"} — if recovery is not possible
|
|
24
|
+
{"action":"revise","plan":{"nodes":[{"id":"...","goal":"...","agent":"<worker or omit>","dependsOn":[],"needsInput":false}],"objective":"..."}} — a NEW plan for the REMAINING objective.
|
|
25
|
+
{"needInfo":"<query>"} — if you need a reality fact before deciding recovery
|
|
26
|
+
{"clarify":"<question>"} — if you need a human decision before deciding recovery
|
|
27
|
+
The revised plan MUST treat the current state as the starting point: do not redo work already done (per the trace); if an artifact already exists, modify it instead of recreating it (idempotent/adaptive).`;
|
|
28
|
+
/**
|
|
29
|
+
* Role adapter: owns a constrained `DirectLlmSubAgent` critic and turns its
|
|
30
|
+
* string output into a typed `ReviewVerdict`.
|
|
31
|
+
*/
|
|
32
|
+
export class LlmReviewStrategy {
|
|
33
|
+
name = 'llm-review';
|
|
34
|
+
/** Best-effort model identifier from the underlying ILlm (for logger
|
|
35
|
+
* attribution). May be undefined for ILlm impls that do not expose one. */
|
|
36
|
+
model;
|
|
37
|
+
agent;
|
|
38
|
+
executionAgent;
|
|
39
|
+
constructor(llm) {
|
|
40
|
+
this.model = llm.model;
|
|
41
|
+
this.agent = new DirectLlmSubAgent('reviewer', llm, {
|
|
42
|
+
systemPrompt: REVIEWER_SYSTEM,
|
|
43
|
+
contextPolicy: 'optional',
|
|
44
|
+
});
|
|
45
|
+
this.executionAgent = new DirectLlmSubAgent('recovery-reviewer', llm, {
|
|
46
|
+
systemPrompt: EXECUTION_REVIEW_SYSTEM,
|
|
47
|
+
contextPolicy: 'optional',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async review(input) {
|
|
51
|
+
const catalog = input.agents
|
|
52
|
+
.map((a) => `- ${a.name}: ${a.description ?? '(no description)'}`)
|
|
53
|
+
.join('\n');
|
|
54
|
+
const contextPrefix = input.ancestorContext
|
|
55
|
+
? `${renderAncestorContext(input.ancestorContext)}\n\n`
|
|
56
|
+
: '';
|
|
57
|
+
const task = `${contextPrefix}User request:\n${input.prompt}\n\nAvailable workers:\n${catalog || '(none)'}\n\nProposed plan (JSON):\n${JSON.stringify(input.plan)}`;
|
|
58
|
+
const res = await this.agent.run({
|
|
59
|
+
task,
|
|
60
|
+
sessionId: input.sessionId,
|
|
61
|
+
signal: input.signal,
|
|
62
|
+
});
|
|
63
|
+
const match = res.output.match(/\{[\s\S]*\}/);
|
|
64
|
+
if (!match)
|
|
65
|
+
throw withUsage(new Error(`Reviewer output did not contain a JSON object: ${res.output.slice(0, 200)}`), res.usage);
|
|
66
|
+
let parsed;
|
|
67
|
+
try {
|
|
68
|
+
parsed = JSON.parse(match[0]);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
throw withUsage(new Error(`Reviewer output contained malformed JSON: ${match[0].slice(0, 200)}`), res.usage);
|
|
72
|
+
}
|
|
73
|
+
if (typeof parsed.needInfo === 'string' && parsed.needInfo.trim()) {
|
|
74
|
+
// Forward LLM usage on the signal path so the coordinator can attribute
|
|
75
|
+
// reviewer spend even when the critic short-circuits with a signal.
|
|
76
|
+
throw new NeedInfoSignal(parsed.needInfo, res.usage);
|
|
77
|
+
}
|
|
78
|
+
if (typeof parsed.clarify === 'string' && parsed.clarify.trim()) {
|
|
79
|
+
throw new ClarifySignal(parsed.clarify, res.usage);
|
|
80
|
+
}
|
|
81
|
+
if (typeof parsed.pass !== 'boolean') {
|
|
82
|
+
throw withUsage(new Error(`Reviewer verdict must have a boolean 'pass': ${match[0].slice(0, 200)}`), res.usage);
|
|
83
|
+
}
|
|
84
|
+
if (parsed.pass === false) {
|
|
85
|
+
if (typeof parsed.feedback !== 'string' ||
|
|
86
|
+
parsed.feedback.trim() === '') {
|
|
87
|
+
throw withUsage(new Error(`Reviewer rejection must include a non-empty 'feedback' string: ${match[0].slice(0, 200)}`), res.usage);
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
verdict: { pass: false, feedback: parsed.feedback },
|
|
91
|
+
usage: res.usage,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return { verdict: { pass: true }, usage: res.usage };
|
|
95
|
+
}
|
|
96
|
+
async reviewExecutionFailure(input) {
|
|
97
|
+
const catalog = input.agents
|
|
98
|
+
.map((a) => `- ${a.name}: ${a.description ?? '(no description)'}`)
|
|
99
|
+
.join('\n');
|
|
100
|
+
const traceText = input.trace
|
|
101
|
+
.map((r) => `- ${r.nodeId} [${r.status}]: ${r.output || r.error || ''}`)
|
|
102
|
+
.join('\n');
|
|
103
|
+
const contextPrefix = input.ancestorContext
|
|
104
|
+
? `${renderAncestorContext(input.ancestorContext)}\n\n`
|
|
105
|
+
: '';
|
|
106
|
+
const task = `${contextPrefix}Objective: ${input.objective ?? '(none)'}\n\nAvailable workers:\n${catalog || '(none)'}\n\nCurrent plan (JSON):\n${JSON.stringify(input.plan)}\n\nExecution trace (current state):\n${traceText || '(nothing completed)'}\n\nFailed step: ${input.failedNodeId}\nError: ${input.error}`;
|
|
107
|
+
const res = await this.executionAgent.run({
|
|
108
|
+
task,
|
|
109
|
+
sessionId: input.sessionId,
|
|
110
|
+
signal: input.signal,
|
|
111
|
+
});
|
|
112
|
+
const match = res.output.match(/\{[\s\S]*\}/);
|
|
113
|
+
if (!match)
|
|
114
|
+
throw withUsage(new Error(`Recovery reviewer output did not contain a JSON object: ${res.output.slice(0, 200)}`), res.usage);
|
|
115
|
+
let parsed;
|
|
116
|
+
try {
|
|
117
|
+
parsed = JSON.parse(match[0]);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw withUsage(new Error(`Recovery reviewer output contained malformed JSON: ${match[0].slice(0, 200)}`), res.usage);
|
|
121
|
+
}
|
|
122
|
+
if (typeof parsed.needInfo === 'string' && parsed.needInfo.trim()) {
|
|
123
|
+
throw new NeedInfoSignal(parsed.needInfo, res.usage);
|
|
124
|
+
}
|
|
125
|
+
if (typeof parsed.clarify === 'string' && parsed.clarify.trim()) {
|
|
126
|
+
throw new ClarifySignal(parsed.clarify, res.usage);
|
|
127
|
+
}
|
|
128
|
+
if (parsed.action === 'abort') {
|
|
129
|
+
return { decision: { action: 'abort' }, usage: res.usage };
|
|
130
|
+
}
|
|
131
|
+
if (parsed.action !== 'revise') {
|
|
132
|
+
throw withUsage(new Error(`Recovery reviewer action must be 'abort' | 'revise': ${match[0].slice(0, 200)}`), res.usage);
|
|
133
|
+
}
|
|
134
|
+
const plan = parsed.plan;
|
|
135
|
+
if (!plan ||
|
|
136
|
+
!Array.isArray(plan.nodes) ||
|
|
137
|
+
plan.nodes.length === 0 ||
|
|
138
|
+
plan.nodes.some((n) => typeof n.id !== 'string' ||
|
|
139
|
+
typeof n.goal !== 'string' ||
|
|
140
|
+
(n.goal ?? '').trim() === '')) {
|
|
141
|
+
throw withUsage(new Error(`Recovery reviewer revise plan must have non-empty nodes with string id+goal: ${match[0].slice(0, 200)}`), res.usage);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
decision: { action: 'revise', revisedPlan: plan },
|
|
145
|
+
usage: res.usage,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=llm-review-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-review-strategy.js","sourceRoot":"","sources":["../../../src/coordinator/dag/llm-review-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExecutionReviewResult, IReviewStrategy, ReviewResult } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
/** Always-pass reviewer; always-abort recovery. Explicit opt-out / test double. */
|
|
3
|
+
export declare class NoopReviewStrategy implements IReviewStrategy {
|
|
4
|
+
readonly name = "noop-review";
|
|
5
|
+
review(): Promise<ReviewResult>;
|
|
6
|
+
reviewExecutionFailure(): Promise<ExecutionReviewResult>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=noop-review-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop-review-strategy.d.ts","sourceRoot":"","sources":["../../../src/coordinator/dag/noop-review-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EACf,YAAY,EACb,MAAM,yBAAyB,CAAC;AAEjC,mFAAmF;AACnF,qBAAa,kBAAmB,YAAW,eAAe;IACxD,QAAQ,CAAC,IAAI,iBAAiB;IACxB,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAG/B,sBAAsB,IAAI,OAAO,CAAC,qBAAqB,CAAC;CAG/D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Always-pass reviewer; always-abort recovery. Explicit opt-out / test double. */
|
|
2
|
+
export class NoopReviewStrategy {
|
|
3
|
+
name = 'noop-review';
|
|
4
|
+
async review() {
|
|
5
|
+
return { verdict: { pass: true } };
|
|
6
|
+
}
|
|
7
|
+
async reviewExecutionFailure() {
|
|
8
|
+
return { decision: { action: 'abort' } };
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=noop-review-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop-review-strategy.js","sourceRoot":"","sources":["../../../src/coordinator/dag/noop-review-strategy.ts"],"names":[],"mappings":"AAMA,mFAAmF;AACnF,MAAM,OAAO,kBAAkB;IACpB,IAAI,GAAG,aAAa,CAAC;IAC9B,KAAK,CAAC,MAAM;QACV,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;IACrC,CAAC;IACD,KAAK,CAAC,sBAAsB;QAC1B,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FinalizerInput, FinalizerResult, IFinalizer } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Default finalizer. Returns the interpreter's already-joined output
|
|
4
|
+
* verbatim — exactly what the DAG coordinator yielded before IFinalizer
|
|
5
|
+
* was introduced. No LLM call; no usage attributed.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PassthroughFinalizer implements IFinalizer {
|
|
8
|
+
readonly name = "passthrough";
|
|
9
|
+
finalize(input: FinalizerInput): Promise<FinalizerResult>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=passthrough-finalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passthrough-finalizer.d.ts","sourceRoot":"","sources":["../../../src/coordinator/dag/passthrough-finalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,UAAU,EACX,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,UAAU;IACrD,QAAQ,CAAC,IAAI,iBAAiB;IAExB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAIhE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default finalizer. Returns the interpreter's already-joined output
|
|
3
|
+
* verbatim — exactly what the DAG coordinator yielded before IFinalizer
|
|
4
|
+
* was introduced. No LLM call; no usage attributed.
|
|
5
|
+
*/
|
|
6
|
+
export class PassthroughFinalizer {
|
|
7
|
+
name = 'passthrough';
|
|
8
|
+
async finalize(input) {
|
|
9
|
+
input.onPartial?.({ kind: 'content', delta: input.interpreterOutput });
|
|
10
|
+
return { output: input.interpreterOutput };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=passthrough-finalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passthrough-finalizer.js","sourceRoot":"","sources":["../../../src/coordinator/dag/passthrough-finalizer.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,MAAM,OAAO,oBAAoB;IACtB,IAAI,GAAG,aAAa,CAAC;IAE9B,KAAK,CAAC,QAAQ,CAAC,KAAqB;QAClC,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC;QACvE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,iBAAiB,EAAE,CAAC;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ContextPath } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Render an ancestor intent path (objective + clarification dialogue + oracle
|
|
4
|
+
* observations) into plain text, prepended to a role's task. Shared by the
|
|
5
|
+
* planner and reviewer role adapters.
|
|
6
|
+
*/
|
|
7
|
+
export declare function renderAncestorContext(ac: ContextPath): string;
|
|
8
|
+
//# sourceMappingURL=render-ancestor-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-ancestor-context.d.ts","sourceRoot":"","sources":["../../../src/coordinator/dag/render-ancestor-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,CAoB7D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render an ancestor intent path (objective + clarification dialogue + oracle
|
|
3
|
+
* observations) into plain text, prepended to a role's task. Shared by the
|
|
4
|
+
* planner and reviewer role adapters.
|
|
5
|
+
*/
|
|
6
|
+
export function renderAncestorContext(ac) {
|
|
7
|
+
const lines = [];
|
|
8
|
+
if (ac.objective) {
|
|
9
|
+
lines.push(`Ancestor objective: ${ac.objective}`);
|
|
10
|
+
}
|
|
11
|
+
if (ac.clarifications.length > 0) {
|
|
12
|
+
lines.push('Prior clarifications:');
|
|
13
|
+
for (const c of ac.clarifications) {
|
|
14
|
+
lines.push(` Q: ${c.question}`);
|
|
15
|
+
lines.push(` A: ${c.answer}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (ac.oracleObservations.length > 0) {
|
|
19
|
+
lines.push('Oracle observations:');
|
|
20
|
+
for (const o of ac.oracleObservations) {
|
|
21
|
+
lines.push(` Query: ${o.query}`);
|
|
22
|
+
lines.push(` Answer: ${o.answer}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return lines.join('\n');
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=render-ancestor-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-ancestor-context.js","sourceRoot":"","sources":["../../../src/coordinator/dag/render-ancestor-context.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAe;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,EAAE,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACpC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,cAAc,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,IAAI,EAAE,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,kBAAkB,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ErrorContext, type ErrorReaction, type IErrorStrategy, type IPlanner, type PlanNode } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Replans a node ONLY for NeedsDecompositionError (the explicit "decompose me"
|
|
4
|
+
* signal). Any other error → abort (a transient MCP/LLM failure is not fixed by
|
|
5
|
+
* decomposition). Stateless: holds the maxReplans ceiling but never counts — the
|
|
6
|
+
* interpreter owns the per-run counter and passes `remainingReplans`.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ReplanErrorStrategy implements IErrorStrategy {
|
|
9
|
+
private readonly planner;
|
|
10
|
+
readonly maxReplans: number;
|
|
11
|
+
readonly name = "replan";
|
|
12
|
+
constructor(planner: IPlanner, maxReplans?: number);
|
|
13
|
+
onNodeFailure(_node: PlanNode, error: unknown, ctx: ErrorContext): Promise<ErrorReaction>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=replan-error-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replan-error-strategy.d.ts","sourceRoot":"","sources":["../../../src/coordinator/dag/replan-error-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,QAAQ,EAEb,KAAK,QAAQ,EACd,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IAGtD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,UAAU;IAHrB,QAAQ,CAAC,IAAI,YAAY;gBAEN,OAAO,EAAE,QAAQ,EACzB,UAAU,SAAI;IAGnB,aAAa,CACjB,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,aAAa,CAAC;CAe1B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NeedsDecompositionError, } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Replans a node ONLY for NeedsDecompositionError (the explicit "decompose me"
|
|
4
|
+
* signal). Any other error → abort (a transient MCP/LLM failure is not fixed by
|
|
5
|
+
* decomposition). Stateless: holds the maxReplans ceiling but never counts — the
|
|
6
|
+
* interpreter owns the per-run counter and passes `remainingReplans`.
|
|
7
|
+
*/
|
|
8
|
+
export class ReplanErrorStrategy {
|
|
9
|
+
planner;
|
|
10
|
+
maxReplans;
|
|
11
|
+
name = 'replan';
|
|
12
|
+
constructor(planner, maxReplans = 4) {
|
|
13
|
+
this.planner = planner;
|
|
14
|
+
this.maxReplans = maxReplans;
|
|
15
|
+
}
|
|
16
|
+
async onNodeFailure(_node, error, ctx) {
|
|
17
|
+
if (!(error instanceof NeedsDecompositionError)) {
|
|
18
|
+
return { action: 'abort' };
|
|
19
|
+
}
|
|
20
|
+
if (ctx.remainingReplans <= 0) {
|
|
21
|
+
return { action: 'abort' };
|
|
22
|
+
}
|
|
23
|
+
const { plan: subPlan } = await this.planner.plan({
|
|
24
|
+
prompt: `${ctx.task}\n\nThis task needs decomposition: ${error.reason}`,
|
|
25
|
+
agents: ctx.agents,
|
|
26
|
+
sessionId: ctx.sessionId,
|
|
27
|
+
signal: ctx.signal,
|
|
28
|
+
});
|
|
29
|
+
return { action: 'replan', subPlan };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=replan-error-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replan-error-strategy.js","sourceRoot":"","sources":["../../../src/coordinator/dag/replan-error-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,uBAAuB,GAExB,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IAGX;IACR;IAHF,IAAI,GAAG,QAAQ,CAAC;IACzB,YACmB,OAAiB,EACzB,aAAa,CAAC;QADN,YAAO,GAAP,OAAO,CAAU;QACzB,eAAU,GAAV,UAAU,CAAI;IACtB,CAAC;IAEJ,KAAK,CAAC,aAAa,CACjB,KAAe,EACf,KAAc,EACd,GAAiB;QAEjB,IAAI,CAAC,CAAC,KAAK,YAAY,uBAAuB,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC7B,CAAC;QACD,IAAI,GAAG,CAAC,gBAAgB,IAAI,CAAC,EAAE,CAAC;YAC9B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC7B,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAChD,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,sCAAsC,KAAK,CAAC,MAAM,EAAE;YACvE,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACvC,CAAC;CACF"}
|