@mcp-abap-adt/llm-agent-server-libs 19.1.2 → 20.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/factories/controller-factory.d.ts +20 -6
- package/dist/factories/controller-factory.d.ts.map +1 -1
- package/dist/factories/controller-factory.js +52 -11
- package/dist/factories/controller-factory.js.map +1 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pipelines/controller.d.ts +4 -2
- package/dist/pipelines/controller.d.ts.map +1 -1
- package/dist/pipelines/controller.js +55 -5
- package/dist/pipelines/controller.js.map +1 -1
- package/dist/pipelines/dag.d.ts +2 -2
- package/dist/pipelines/dag.d.ts.map +1 -1
- package/dist/pipelines/dag.js +4 -3
- package/dist/pipelines/dag.js.map +1 -1
- package/dist/pipelines/flat.d.ts.map +1 -1
- package/dist/pipelines/flat.js +2 -1
- package/dist/pipelines/flat.js.map +1 -1
- package/dist/pipelines/linear.d.ts.map +1 -1
- package/dist/pipelines/linear.js +2 -1
- package/dist/pipelines/linear.js.map +1 -1
- package/dist/pipelines/register-skill-sources.d.ts +21 -0
- package/dist/pipelines/register-skill-sources.d.ts.map +1 -0
- package/dist/pipelines/register-skill-sources.js +57 -0
- package/dist/pipelines/register-skill-sources.js.map +1 -0
- package/dist/pipelines/server-context.d.ts +37 -1
- package/dist/pipelines/server-context.d.ts.map +1 -1
- package/dist/pipelines/server-context.js.map +1 -1
- package/dist/pipelines/stepper.d.ts +2 -2
- package/dist/pipelines/stepper.js +2 -2
- package/dist/smart-agent/config.d.ts +1 -1
- package/dist/smart-agent/config.d.ts.map +1 -1
- package/dist/smart-agent/config.js +7 -3
- package/dist/smart-agent/config.js.map +1 -1
- package/dist/smart-agent/controller/artifacts.d.ts +116 -0
- package/dist/smart-agent/controller/artifacts.d.ts.map +1 -0
- package/dist/smart-agent/controller/artifacts.js +192 -0
- package/dist/smart-agent/controller/artifacts.js.map +1 -0
- package/dist/smart-agent/controller/board.d.ts +73 -0
- package/dist/smart-agent/controller/board.d.ts.map +1 -0
- package/dist/smart-agent/controller/board.js +233 -0
- package/dist/smart-agent/controller/board.js.map +1 -0
- package/dist/smart-agent/controller/controller-coordinator-handler.d.ts +75 -7
- package/dist/smart-agent/controller/controller-coordinator-handler.d.ts.map +1 -1
- package/dist/smart-agent/controller/controller-coordinator-handler.js +929 -66
- package/dist/smart-agent/controller/controller-coordinator-handler.js.map +1 -1
- package/dist/smart-agent/controller/finalizer.d.ts +48 -0
- package/dist/smart-agent/controller/finalizer.d.ts.map +1 -0
- package/dist/smart-agent/controller/finalizer.js +126 -0
- package/dist/smart-agent/controller/finalizer.js.map +1 -0
- package/dist/smart-agent/controller/memorizer.d.ts +2 -2
- package/dist/smart-agent/controller/memorizer.d.ts.map +1 -1
- package/dist/smart-agent/controller/memorizer.js +2 -2
- package/dist/smart-agent/controller/memorizer.js.map +1 -1
- package/dist/smart-agent/controller/outcome.d.ts +28 -0
- package/dist/smart-agent/controller/outcome.d.ts.map +1 -0
- package/dist/smart-agent/controller/outcome.js +30 -0
- package/dist/smart-agent/controller/outcome.js.map +1 -0
- package/dist/smart-agent/controller/planner.d.ts +41 -14
- package/dist/smart-agent/controller/planner.d.ts.map +1 -1
- package/dist/smart-agent/controller/planner.js +149 -73
- package/dist/smart-agent/controller/planner.js.map +1 -1
- package/dist/smart-agent/controller/reviewer.d.ts +48 -0
- package/dist/smart-agent/controller/reviewer.d.ts.map +1 -0
- package/dist/smart-agent/controller/reviewer.js +116 -0
- package/dist/smart-agent/controller/reviewer.js.map +1 -0
- package/dist/smart-agent/controller/run-scope.d.ts +50 -0
- package/dist/smart-agent/controller/run-scope.d.ts.map +1 -0
- package/dist/smart-agent/controller/run-scope.js +99 -0
- package/dist/smart-agent/controller/run-scope.js.map +1 -0
- package/dist/smart-agent/controller/session-bundle.d.ts +5 -0
- package/dist/smart-agent/controller/session-bundle.d.ts.map +1 -1
- package/dist/smart-agent/controller/session-bundle.js +27 -0
- package/dist/smart-agent/controller/session-bundle.js.map +1 -1
- package/dist/smart-agent/controller/types.d.ts +124 -15
- package/dist/smart-agent/controller/types.d.ts.map +1 -1
- package/dist/smart-agent/controller/types.js +30 -1
- package/dist/smart-agent/controller/types.js.map +1 -1
- package/dist/smart-agent/embedder-knowledge-index.d.ts +28 -0
- package/dist/smart-agent/embedder-knowledge-index.d.ts.map +1 -0
- package/dist/smart-agent/embedder-knowledge-index.js +71 -0
- package/dist/smart-agent/embedder-knowledge-index.js.map +1 -0
- package/dist/smart-agent/jsonl-knowledge-backend.d.ts +26 -10
- package/dist/smart-agent/jsonl-knowledge-backend.d.ts.map +1 -1
- package/dist/smart-agent/jsonl-knowledge-backend.js +81 -9
- package/dist/smart-agent/jsonl-knowledge-backend.js.map +1 -1
- package/dist/smart-agent/pg-pool.d.ts +58 -0
- package/dist/smart-agent/pg-pool.d.ts.map +1 -0
- package/dist/smart-agent/pg-pool.js +149 -0
- package/dist/smart-agent/pg-pool.js.map +1 -0
- package/dist/smart-agent/skill-plugins-config.d.ts +97 -0
- package/dist/smart-agent/skill-plugins-config.d.ts.map +1 -0
- package/dist/smart-agent/skill-plugins-config.js +318 -0
- package/dist/smart-agent/skill-plugins-config.js.map +1 -0
- package/dist/smart-agent/skill-plugins-config.test.d.ts +2 -0
- package/dist/smart-agent/skill-plugins-config.test.d.ts.map +1 -0
- package/dist/smart-agent/skill-plugins-config.test.js.map +1 -0
- package/dist/smart-agent/skill-plugins-host-factory.d.ts +98 -0
- package/dist/smart-agent/skill-plugins-host-factory.d.ts.map +1 -0
- package/dist/smart-agent/skill-plugins-host-factory.js +284 -0
- package/dist/smart-agent/skill-plugins-host-factory.js.map +1 -0
- package/dist/smart-agent/skill-plugins-host-factory.test.d.ts +2 -0
- package/dist/smart-agent/skill-plugins-host-factory.test.d.ts.map +1 -0
- package/dist/smart-agent/skill-plugins-host-factory.test.js.map +1 -0
- package/dist/smart-agent/smart-server.d.ts +25 -0
- package/dist/smart-agent/smart-server.d.ts.map +1 -1
- package/dist/smart-agent/smart-server.js +141 -7
- package/dist/smart-agent/smart-server.js.map +1 -1
- package/package.json +9 -7
|
@@ -1,51 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mintCreateStepIds, mintReplanStepIds, } from './artifacts.js';
|
|
2
|
+
import { extractJsonObject } from './controller-coordinator-handler.js';
|
|
2
3
|
import { appendHint } from './prompts.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
async next(input) {
|
|
31
|
-
const { bundle, prompt, retrying, logUsage } = input;
|
|
32
|
-
const res = await this.planner.send([
|
|
33
|
-
{
|
|
34
|
-
role: 'system',
|
|
35
|
-
content: appendHint(PLANNER_SYSTEM, this.hint) + (retrying ? RETRY_HINT : ''),
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
role: 'user',
|
|
39
|
-
content: `Goal: ${bundle.goal}\nProgress:${bundle.plannerPrivate}\nRequest: ${prompt}`,
|
|
40
|
-
},
|
|
41
|
-
]);
|
|
42
|
-
logUsage?.('planner', res.usage);
|
|
43
|
-
if (res.kind !== 'content')
|
|
44
|
-
return null;
|
|
45
|
-
return parseNextStep(res.content);
|
|
46
|
-
}
|
|
4
|
+
import { MAX_REQUIRE_CHARS, MAX_REQUIRES, validateRequires, } from './types.js';
|
|
5
|
+
// Built from the validation constants so the prompt cap can NEVER drift from what
|
|
6
|
+
// the parser enforces (no duplicated literals). Appended to EVERY planner/replan
|
|
7
|
+
// prompt as a HARD invariant so step instructions/requires are English (stable
|
|
8
|
+
// tool selection against the English-translated catalog) and the requires count is
|
|
9
|
+
// bounded.
|
|
10
|
+
export const ENGLISH_INSTRUCTIONS_RULE = ' Step `instructions` AND `requires` references MUST be written in English — ' +
|
|
11
|
+
"always, regardless of the language of the user's request. This is a hard " +
|
|
12
|
+
'contract: the executor selects tools by semantic match against an ' +
|
|
13
|
+
'English-translated catalog, and the reviewer matches `requires` against stored ' +
|
|
14
|
+
'artifacts — so non-English instructions/requires break both. ' +
|
|
15
|
+
`List at MOST ${MAX_REQUIRES} \`requires\`, each a SHORT reference (a few words, ` +
|
|
16
|
+
`≤ ${MAX_REQUIRE_CHARS} chars) — not pasted content. (The user-facing answer is ` +
|
|
17
|
+
"composed separately in the user's language.)";
|
|
18
|
+
/** Append a non-empty recall block to a user message, preserving the agnostic
|
|
19
|
+
* message byte-for-byte when the block is empty. */
|
|
20
|
+
function withSkillsBlock(userContent, block) {
|
|
21
|
+
return block ? `${userContent}\n\n${block}` : userContent;
|
|
22
|
+
}
|
|
23
|
+
/** The planner's progress context. With a live board, render the AUTHORITATIVE
|
|
24
|
+
* structured board AND the plannerPrivate tail — the latter carries non-board
|
|
25
|
+
* deltas the planner still needs (clarify answers, legacy external-tool result).
|
|
26
|
+
* An empty board → plannerPrivate alone, byte-identical to the legacy prompt. */
|
|
27
|
+
function progressBlock(bundle, boardText) {
|
|
28
|
+
return boardText && boardText.length > 0
|
|
29
|
+
? `${boardText}\n${bundle.plannerPrivate}`
|
|
30
|
+
: bundle.plannerPrivate;
|
|
47
31
|
}
|
|
48
|
-
const CREATE_PLAN_SYSTEM = 'You are the planner. Produce the COMPLETE, ordered plan that covers the ENTIRE ' +
|
|
32
|
+
export const CREATE_PLAN_SYSTEM = 'You are the planner. Produce the COMPLETE, ordered plan that covers the ENTIRE ' +
|
|
49
33
|
'goal NOW, as a SINGLE JSON object: {"plan":[{"name":...,"instructions":...}, ...]}. ' +
|
|
50
34
|
'This is plan-once: there will be NO chance to add steps later (a replan happens ' +
|
|
51
35
|
'only if a step FAILS), so the plan MUST already contain every step the goal ' +
|
|
@@ -71,16 +55,18 @@ const CREATE_PLAN_SYSTEM = 'You are the planner. Produce the COMPLETE, ordered p
|
|
|
71
55
|
'Do NOT add a final step ' +
|
|
72
56
|
'that summarizes, formats, or answers the user — a separate finalizer composes ' +
|
|
73
57
|
'the answer from the fetched results, so the last step must be the last ' +
|
|
74
|
-
'data-fetch/action the goal needs. Output JSON only.'
|
|
75
|
-
|
|
58
|
+
'data-fetch/action the goal needs. Output JSON only.' +
|
|
59
|
+
ENGLISH_INSTRUCTIONS_RULE;
|
|
60
|
+
export const REPLAN_SYSTEM = 'You are the planner. A step just FAILED. Given the goal, the progress so far ' +
|
|
76
61
|
'(fetched results + the failure), produce a REVISED, MINIMAL plan for the ' +
|
|
77
62
|
'REMAINING work as {"plan":[{"name":...,"instructions":...}, ...]}. Plan only ' +
|
|
78
63
|
'the data-fetch/action steps still required; describe each step by INTENT — do ' +
|
|
79
64
|
'NOT name or choose a specific tool, the executor selects it. Do NOT add a ' +
|
|
80
65
|
'final summarize/' +
|
|
81
66
|
'answer step (a separate finalizer composes the answer). If the goal is ' +
|
|
82
|
-
'already satisfied despite the failure, return {"plan":[]}. Output JSON only.'
|
|
83
|
-
|
|
67
|
+
'already satisfied despite the failure, return {"plan":[]}. Output JSON only.' +
|
|
68
|
+
ENGLISH_INSTRUCTIONS_RULE;
|
|
69
|
+
export const EXTERNAL_RESULT_REPLAN_SYSTEM = 'You are the planner. A NEW external tool result just arrived (see Progress) — ' +
|
|
84
70
|
'this is NOT a failure. Given the goal and the progress (including the new ' +
|
|
85
71
|
'result), produce a REVISED, MINIMAL plan for the REMAINING work as ' +
|
|
86
72
|
'{"plan":[{"name":...,"instructions":...}, ...]}. Plan only the data-fetch/' +
|
|
@@ -88,7 +74,32 @@ const EXTERNAL_RESULT_REPLAN_SYSTEM = 'You are the planner. A NEW external tool
|
|
|
88
74
|
'choose a specific tool, the executor selects it. Do NOT add a final summarize/' +
|
|
89
75
|
'answer step (a ' +
|
|
90
76
|
'separate finalizer composes the answer). If the goal is already satisfied by ' +
|
|
91
|
-
'the result, return {"plan":[]}. Output JSON only.'
|
|
77
|
+
'the result, return {"plan":[]}. Output JSON only.' +
|
|
78
|
+
ENGLISH_INSTRUCTIONS_RULE;
|
|
79
|
+
/** Smart-executor granularity clause (§C). A capable executor can self-expand a
|
|
80
|
+
* coarse step inside its own tool-loop, so the planner MAY plan coarse. Clarifies
|
|
81
|
+
* that the base's "one concrete action" means one INTENT — a coarse batch step is
|
|
82
|
+
* one intent, not a planner-side per-item fan-out. AGNOSTIC: no tool names. */
|
|
83
|
+
const SMART_GRANULARITY = ' GRANULARITY (smart executor): a step MAY be COARSE — a single intent that ' +
|
|
84
|
+
'covers a set of related items (e.g. "read every item referenced by the prior ' +
|
|
85
|
+
'result"); a capable executor enumerates and processes each item WITHIN ITS OWN ' +
|
|
86
|
+
'tool-loop, and control returns to the reviewer after the coarse step. This does ' +
|
|
87
|
+
'NOT violate "one concrete action": a coarse batch is ONE intent. PREFER fewer ' +
|
|
88
|
+
'coarse steps over enumerating items yourself.';
|
|
89
|
+
/** Weak-executor granularity clause (§C). A weak executor cannot be trusted to
|
|
90
|
+
* self-expand, so every step is exactly one atomic action. (Deferred discovery
|
|
91
|
+
* fan-out for plan-time-unknowable batches — §D — is Phase 4; in Phase 3 the weak
|
|
92
|
+
* planner just plans the finest grain it can.) AGNOSTIC: no tool names. */
|
|
93
|
+
const WEAK_GRANULARITY = ' GRANULARITY (weak executor): each step is EXACTLY ONE ATOMIC action the ' +
|
|
94
|
+
'executor performs in a SINGLE tool use. NEVER emit a coarse/batch step and ' +
|
|
95
|
+
'NEVER rely on the executor to self-expand a step — the executor handles one ' +
|
|
96
|
+
'action at a time; if work spans several actions, emit that many steps.';
|
|
97
|
+
export const SMART_CREATE_PLAN_SYSTEM = CREATE_PLAN_SYSTEM + SMART_GRANULARITY;
|
|
98
|
+
export const SMART_REPLAN_SYSTEM = REPLAN_SYSTEM + SMART_GRANULARITY;
|
|
99
|
+
export const SMART_EXTERNAL_RESULT_REPLAN_SYSTEM = EXTERNAL_RESULT_REPLAN_SYSTEM + SMART_GRANULARITY;
|
|
100
|
+
export const WEAK_CREATE_PLAN_SYSTEM = CREATE_PLAN_SYSTEM + WEAK_GRANULARITY;
|
|
101
|
+
export const WEAK_REPLAN_SYSTEM = REPLAN_SYSTEM + WEAK_GRANULARITY;
|
|
102
|
+
export const WEAK_EXTERNAL_RESULT_REPLAN_SYSTEM = EXTERNAL_RESULT_REPLAN_SYSTEM + WEAK_GRANULARITY;
|
|
92
103
|
const FINALIZE_SYSTEM = 'All planned steps are complete. Using the progress below (the fetched results), ' +
|
|
93
104
|
'write the final answer to the user request. Plain text, no JSON.';
|
|
94
105
|
/** Parse {"plan":[{name,instructions},...]} from a (possibly fenced) reply.
|
|
@@ -110,10 +121,14 @@ function parsePlan(content) {
|
|
|
110
121
|
if (typeof s.name !== 'string' || typeof s.instructions !== 'string') {
|
|
111
122
|
return null; // malformed step → format failure (handler retries)
|
|
112
123
|
}
|
|
124
|
+
const req = validateRequires(raw.requires);
|
|
125
|
+
if (req === false)
|
|
126
|
+
return null; // malformed requires → format failure → retry
|
|
113
127
|
steps.push({
|
|
114
128
|
name: s.name,
|
|
115
129
|
instructions: s.instructions,
|
|
116
130
|
...(s.type ? { type: s.type } : {}),
|
|
131
|
+
...(req ? { requires: req } : {}),
|
|
117
132
|
});
|
|
118
133
|
}
|
|
119
134
|
return steps;
|
|
@@ -122,70 +137,111 @@ function parsePlan(content) {
|
|
|
122
137
|
return null;
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
|
-
|
|
140
|
+
/** Queue a plan decision for the controller to persist (§A boundary: the planner
|
|
141
|
+
* CONSTRUCTS the decision; the controller does the durable write). */
|
|
142
|
+
function recordDecision(bundle, decision) {
|
|
143
|
+
if (!bundle.pendingPlanDecisions)
|
|
144
|
+
bundle.pendingPlanDecisions = [];
|
|
145
|
+
bundle.pendingPlanDecisions.push(decision);
|
|
146
|
+
}
|
|
147
|
+
export class SmartExecutorPlanner {
|
|
126
148
|
planner;
|
|
127
149
|
hint;
|
|
150
|
+
skillsRecall;
|
|
128
151
|
// No budget field: replans are bounded by the loop's maxSteps (a failed step
|
|
129
152
|
// bumps stepsUsed in runStep). Replan-specific budgeting is the deferred
|
|
130
153
|
// "limits as a selectable strategy" work.
|
|
131
154
|
constructor(planner,
|
|
132
155
|
/** Optional consumer domain hint appended to every agnostic planner/
|
|
133
156
|
* create-plan/replan/finalize prompt this planner emits. */
|
|
134
|
-
hint
|
|
157
|
+
hint,
|
|
158
|
+
/** Optional controller-own skills recall hook (B4). Queried before each
|
|
159
|
+
* create-plan/replan; its block is injected into the user message. */
|
|
160
|
+
skillsRecall) {
|
|
135
161
|
this.planner = planner;
|
|
136
162
|
this.hint = hint;
|
|
163
|
+
this.skillsRecall = skillsRecall;
|
|
164
|
+
}
|
|
165
|
+
/** Prompt seam — overridden by WeakExecutorPlanner for atomic granularity (§C). */
|
|
166
|
+
get createPlanSystem() {
|
|
167
|
+
return SMART_CREATE_PLAN_SYSTEM;
|
|
168
|
+
}
|
|
169
|
+
get replanSystem() {
|
|
170
|
+
return SMART_REPLAN_SYSTEM;
|
|
171
|
+
}
|
|
172
|
+
get externalResultReplanSystem() {
|
|
173
|
+
return SMART_EXTERNAL_RESULT_REPLAN_SYSTEM;
|
|
137
174
|
}
|
|
138
175
|
async next(input) {
|
|
139
|
-
const { bundle, prompt, lastOutcome, resumedExternal, retrying, logUsage } = input;
|
|
176
|
+
const { bundle, prompt, lastOutcome, resumedExternal, retrying, logUsage, options, boardText, } = input;
|
|
140
177
|
// 1. No plan yet → create it.
|
|
141
178
|
if (!bundle.plan) {
|
|
142
|
-
const plan = await this.callPlan(
|
|
179
|
+
const plan = await this.callPlan(this.createPlanSystem, bundle, prompt, retrying, logUsage, [], options, boardText);
|
|
143
180
|
// An EMPTY plan from createPlan is invalid: it would skip straight to the
|
|
144
181
|
// finalizer and answer WITHOUT fetching the required data. Treat it as a
|
|
145
182
|
// format failure → handler re-asks (bounded by maxRetries). (An empty plan
|
|
146
183
|
// is only valid on REPLAN, where it means "remaining work is done".)
|
|
147
184
|
if (plan === null || plan.length === 0)
|
|
148
185
|
return null;
|
|
149
|
-
bundle.
|
|
186
|
+
const minted = mintCreateStepIds(plan, bundle.runId ?? '');
|
|
187
|
+
bundle.plan = minted;
|
|
150
188
|
bundle.planCursor = 0;
|
|
151
|
-
|
|
189
|
+
recordDecision(bundle, {
|
|
190
|
+
kind: 'create',
|
|
191
|
+
runId: bundle.runId ?? '',
|
|
192
|
+
steps: minted,
|
|
193
|
+
});
|
|
194
|
+
return this.stepAtCursor(bundle, prompt, logUsage, boardText);
|
|
152
195
|
}
|
|
153
196
|
// 2. Previous step failed, OR an external-tool result just arrived → replan
|
|
154
197
|
// the remainder from the cursor. The planner reads plannerPrivate (which
|
|
155
198
|
// now holds the failure/external result), so the revised plan incorporates
|
|
156
199
|
// it — no reliance on the executor seeing it. Use the matching prompt: an
|
|
157
200
|
// external result is NOT a failure, so it gets its own framing.
|
|
158
|
-
if (lastOutcome === 'failed' ||
|
|
201
|
+
if (lastOutcome === 'failed' ||
|
|
202
|
+
lastOutcome === 'partial' ||
|
|
203
|
+
resumedExternal) {
|
|
159
204
|
const system = resumedExternal
|
|
160
|
-
?
|
|
161
|
-
:
|
|
205
|
+
? this.externalResultReplanSystem
|
|
206
|
+
: this.replanSystem;
|
|
162
207
|
const cursor = bundle.planCursor ?? 0;
|
|
163
208
|
// Steps before the cursor already ran successfully — pass them so the replan
|
|
164
209
|
// plans only the remaining work and never repeats a completed step.
|
|
165
210
|
const completed = bundle.plan.slice(0, cursor);
|
|
166
|
-
const rest = await this.callPlan(system, bundle, prompt, retrying, logUsage, completed);
|
|
211
|
+
const rest = await this.callPlan(system, bundle, prompt, retrying, logUsage, completed, options, boardText);
|
|
167
212
|
if (rest === null)
|
|
168
213
|
return null;
|
|
169
|
-
|
|
214
|
+
const anchor = bundle.plan[cursor]?.stepId ?? '';
|
|
215
|
+
const mintedRest = mintReplanStepIds(rest, bundle.runId ?? '', anchor);
|
|
216
|
+
bundle.plan = [...bundle.plan.slice(0, cursor), ...mintedRest];
|
|
217
|
+
recordDecision(bundle, {
|
|
218
|
+
kind: 'replan',
|
|
219
|
+
runId: bundle.runId ?? '',
|
|
220
|
+
anchor,
|
|
221
|
+
steps: mintedRest,
|
|
222
|
+
});
|
|
170
223
|
// The failure has now been consumed into the revised plan. Clear the durable
|
|
171
224
|
// failure marker BEFORE the (possible) finalize below, so that: a crash after
|
|
172
225
|
// this replan does NOT replan again on resume, and a finalizer error after an
|
|
173
226
|
// empty replan retries only the finalizer (not another replan).
|
|
174
227
|
bundle.lastOutcome = undefined;
|
|
175
|
-
return this.stepAtCursor(bundle, prompt, logUsage);
|
|
228
|
+
return this.stepAtCursor(bundle, prompt, logUsage, boardText);
|
|
176
229
|
}
|
|
177
230
|
// 3. Otherwise emit the step at the cursor (or finalize). The cursor is
|
|
178
231
|
// advanced by commit() AFTER a step succeeds — NOT here — so the advance
|
|
179
232
|
// is persisted together with the step result (see Task 4), and a resume
|
|
180
233
|
// with lastOutcome=undefined continues from the next uncompleted step
|
|
181
234
|
// instead of repeating the last one.
|
|
182
|
-
return this.stepAtCursor(bundle, prompt, logUsage);
|
|
235
|
+
return this.stepAtCursor(bundle, prompt, logUsage, boardText);
|
|
183
236
|
}
|
|
184
237
|
/** Commit the just-finished step's outcome so the advance is persisted with it.
|
|
185
238
|
* On success the cursor moves to the next step; a failure leaves the cursor so
|
|
186
239
|
* the next next() can replan from it. (No LLM call — pure bookkeeping.) */
|
|
187
240
|
commit(bundle, outcome) {
|
|
188
|
-
|
|
241
|
+
// 'advanced' and 'partial' both advance the cursor: the accepted part of a
|
|
242
|
+
// partial is committed and must not be re-run (the remainder is replanned at
|
|
243
|
+
// the next cursor). 'failed' leaves the cursor for next()'s replan.
|
|
244
|
+
if (outcome === 'advanced' || outcome === 'partial') {
|
|
189
245
|
bundle.planCursor = (bundle.planCursor ?? 0) + 1;
|
|
190
246
|
}
|
|
191
247
|
}
|
|
@@ -193,7 +249,7 @@ export class AdaptivePlanner {
|
|
|
193
249
|
* Returns null when the finalizer call fails (error / unexpected tool_call) so
|
|
194
250
|
* the handler retries it (bounded by maxRetries) instead of emitting a fake
|
|
195
251
|
* "completed" answer. */
|
|
196
|
-
async stepAtCursor(bundle, prompt, logUsage) {
|
|
252
|
+
async stepAtCursor(bundle, prompt, logUsage, boardText) {
|
|
197
253
|
const plan = bundle.plan ?? [];
|
|
198
254
|
const cursor = bundle.planCursor ?? 0;
|
|
199
255
|
if (cursor >= plan.length) {
|
|
@@ -201,7 +257,7 @@ export class AdaptivePlanner {
|
|
|
201
257
|
{ role: 'system', content: appendHint(FINALIZE_SYSTEM, this.hint) },
|
|
202
258
|
{
|
|
203
259
|
role: 'user',
|
|
204
|
-
content: `Goal: ${bundle.goal}\nRequest: ${prompt}\nProgress:${bundle
|
|
260
|
+
content: `Goal: ${bundle.goal}\nRequest: ${prompt}\nProgress:${progressBlock(bundle, boardText)}`,
|
|
205
261
|
},
|
|
206
262
|
]);
|
|
207
263
|
logUsage?.('finalizer', res.usage);
|
|
@@ -213,13 +269,19 @@ export class AdaptivePlanner {
|
|
|
213
269
|
}
|
|
214
270
|
return { kind: 'next', step: plan[cursor] };
|
|
215
271
|
}
|
|
216
|
-
async callPlan(system, bundle, prompt, retrying, logUsage, completed = []) {
|
|
272
|
+
async callPlan(system, bundle, prompt, retrying, logUsage, completed = [], options, boardText) {
|
|
217
273
|
// On replan, the planner MUST know which steps already ran (their results are
|
|
218
274
|
// in Progress / the step-result collection) so it plans ONLY the remaining
|
|
219
275
|
// work and never re-executes a completed step.
|
|
220
276
|
const completedBlock = completed.length
|
|
221
277
|
? `\nALREADY-EXECUTED steps — their results are in Progress above; do NOT plan or repeat these, plan only what is still missing:\n${completed.map((s) => `- ${s.name}`).join('\n')}`
|
|
222
278
|
: '';
|
|
279
|
+
// Recall the configured controller skill group BEFORE the LLM call and inject
|
|
280
|
+
// its bounded block. When the hook is absent OR returns '' the user message is
|
|
281
|
+
// byte-identical to the agnostic prompt (the measurement toggle).
|
|
282
|
+
const skillsBlock = this.skillsRecall
|
|
283
|
+
? await this.skillsRecall(bundle.goal, options)
|
|
284
|
+
: '';
|
|
223
285
|
const res = await this.planner.send([
|
|
224
286
|
{
|
|
225
287
|
role: 'system',
|
|
@@ -230,7 +292,7 @@ export class AdaptivePlanner {
|
|
|
230
292
|
},
|
|
231
293
|
{
|
|
232
294
|
role: 'user',
|
|
233
|
-
content: `Goal: ${bundle.goal}\nProgress:${bundle
|
|
295
|
+
content: withSkillsBlock(`Goal: ${bundle.goal}\nProgress:${progressBlock(bundle, boardText)}${completedBlock}\nRequest: ${prompt}`, skillsBlock),
|
|
234
296
|
},
|
|
235
297
|
]);
|
|
236
298
|
logUsage?.('planner', res.usage);
|
|
@@ -239,9 +301,23 @@ export class AdaptivePlanner {
|
|
|
239
301
|
return parsePlan(res.content);
|
|
240
302
|
}
|
|
241
303
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
304
|
+
/** Weak-executor planner (§C): the same plan-first engine as SmartExecutorPlanner,
|
|
305
|
+
* but with the finest-grain create/replan prompts (one action per step). Phase 4
|
|
306
|
+
* adds deferred discovery expansion to this class; Phase 3 differs only by prompt. */
|
|
307
|
+
export class WeakExecutorPlanner extends SmartExecutorPlanner {
|
|
308
|
+
get createPlanSystem() {
|
|
309
|
+
return WEAK_CREATE_PLAN_SYSTEM;
|
|
310
|
+
}
|
|
311
|
+
get replanSystem() {
|
|
312
|
+
return WEAK_REPLAN_SYSTEM;
|
|
313
|
+
}
|
|
314
|
+
get externalResultReplanSystem() {
|
|
315
|
+
return WEAK_EXTERNAL_RESULT_REPLAN_SYSTEM;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export function makeControllerPlanner(kind, planner, hint, skillsRecall) {
|
|
319
|
+
return kind === 'weak-executor'
|
|
320
|
+
? new WeakExecutorPlanner(planner, hint, skillsRecall)
|
|
321
|
+
: new SmartExecutorPlanner(planner, hint, skillsRecall);
|
|
246
322
|
}
|
|
247
323
|
//# sourceMappingURL=planner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/smart-agent/controller/planner.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/smart-agent/controller/planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { LlmUsage } from '@mcp-abap-adt/llm-agent';
|
|
2
|
+
import type { ReviewOutcome } from './outcome.js';
|
|
3
|
+
import type { ISubagentClient } from './subagent-client.js';
|
|
4
|
+
import type { Step } from './types.js';
|
|
5
|
+
/** One reference's evidence: the closest stored artifact's content (or none). */
|
|
6
|
+
export interface Evidence {
|
|
7
|
+
ref: string;
|
|
8
|
+
hit: boolean;
|
|
9
|
+
topArtifact?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ReviewOpts {
|
|
12
|
+
hint?: string;
|
|
13
|
+
logUsage?: (role: string, u?: LlmUsage) => void;
|
|
14
|
+
/** Defensive cap on the returned `digest` (§B). Defaults to 500 when omitted. */
|
|
15
|
+
maxDigestChars?: number;
|
|
16
|
+
}
|
|
17
|
+
/** The reviewer's return: EITHER an authoritative step Outcome (incl. a genuine
|
|
18
|
+
* `failed` verdict → step replan), OR a judge-failure — the reviewer could not
|
|
19
|
+
* produce ANY usable verdict (provider/transport error, unparsable JSON, or a
|
|
20
|
+
* missing/invalid status). The controller re-asks a judge-failure within
|
|
21
|
+
* `maxReviewRetries` and, on exhaustion, DEGRADES it to a failed step (→ replan),
|
|
22
|
+
* bounded by `maxStepAttempts`/`maxSteps` — it does NOT abort the run. (A
|
|
23
|
+
* well-formed but contradictory verdict — ok/exists/partial with empty `approved` —
|
|
24
|
+
* is coerced to a `failed` Outcome in `parseReview`, NOT a judge-failure.) */
|
|
25
|
+
export type ReviewResult = {
|
|
26
|
+
kind: 'outcome';
|
|
27
|
+
outcome: ReviewOutcome;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'judge-failure';
|
|
30
|
+
reason: string;
|
|
31
|
+
};
|
|
32
|
+
/** Separate judging role. The controller depends ONLY on this; `status` always
|
|
33
|
+
* comes through a well-formed Outcome. Default impl is LLM-backed; swappable. */
|
|
34
|
+
export interface IReviewer {
|
|
35
|
+
review(step: Step, evidence: readonly Evidence[], executorResult: string, opts: ReviewOpts): Promise<ReviewResult>;
|
|
36
|
+
}
|
|
37
|
+
export declare class LlmReviewer implements IReviewer {
|
|
38
|
+
private readonly client;
|
|
39
|
+
constructor(client: ISubagentClient);
|
|
40
|
+
review(step: Step, evidence: readonly Evidence[], executorResult: string, opts: ReviewOpts): Promise<ReviewResult>;
|
|
41
|
+
}
|
|
42
|
+
/** Parse a reviewer reply into a ReviewResult. A well-formed verdict (any of
|
|
43
|
+
* ok/exists/partial/failed) is an `outcome`; ok/exists/partial with EMPTY approved
|
|
44
|
+
* is coerced to a `failed` outcome (contradictory → replan, not abort). Only a
|
|
45
|
+
* truly unusable reply — unparsable JSON or missing/invalid status — is a
|
|
46
|
+
* `judge-failure` (re-ask within budget, then degrade to a failed step). */
|
|
47
|
+
export declare function parseReview(content: string, maxDigestChars?: number): ReviewResult;
|
|
48
|
+
//# sourceMappingURL=reviewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewer.d.ts","sourceRoot":"","sources":["../../../src/smart-agent/controller/reviewer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;IAChD,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;+EAO+E;AAC/E,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C;kFACkF;AAClF,MAAM,WAAW,SAAS;IACxB,MAAM,CACJ,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAC7B,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1B;AAwBD,qBAAa,WAAY,YAAW,SAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,eAAe;IAE9C,MAAM,CACV,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAC7B,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC;CA8BzB;AAED;;;;6EAI6E;AAC7E,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,cAAc,SAAM,GACnB,YAAY,CAyDd"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { extractJsonObject } from './controller-coordinator-handler.js';
|
|
2
|
+
import { appendHint } from './prompts.js';
|
|
3
|
+
const REVIEWER_SYSTEM = 'You are the reviewer. You did NOT do the work — you JUDGE it. Given the ' +
|
|
4
|
+
"step intent, the per-reference evidence, and the executor's result, decide " +
|
|
5
|
+
'the authoritative outcome and return a SINGLE JSON object: ' +
|
|
6
|
+
'{"status":"ok"|"exists"|"failed"|"partial","approved":<content to keep>,' +
|
|
7
|
+
'"remainder":<what is still missing>,"note":<short reason>,' +
|
|
8
|
+
'"digest":<a SHORT plain-text extract of what this step established that the ' +
|
|
9
|
+
'PLANNER needs to decide the next step — e.g. the key names/ids/outcome, NOT ' +
|
|
10
|
+
'the full content>}. ' +
|
|
11
|
+
'Use "ok" when the step is fully satisfied, "exists" when the target already ' +
|
|
12
|
+
'existed (idempotent no-op success), "partial" when only part is done (put the ' +
|
|
13
|
+
'accepted content in "approved" and what remains in "remainder"), "failed" when ' +
|
|
14
|
+
'the result does not satisfy the step. "approved" MUST be non-empty for ok/' +
|
|
15
|
+
'exists/partial. Judge ONLY from the evidence + result; do NOT invent facts. ' +
|
|
16
|
+
'The evidence lists, per required reference, the CLOSEST stored artifact (or ' +
|
|
17
|
+
'MISSING). Decide for YOURSELF whether that artifact actually satisfies the ' +
|
|
18
|
+
'reference — a closest-match artifact may be irrelevant; treat an unsatisfied or ' +
|
|
19
|
+
'missing required reference as "failed" (note: "missing input: <ref>"). ' +
|
|
20
|
+
'The "digest" is REQUIRED and MUST be a non-empty plain-text string (keep it ' +
|
|
21
|
+
'brief — the full result is stored separately). ' +
|
|
22
|
+
'Output JSON only.';
|
|
23
|
+
export class LlmReviewer {
|
|
24
|
+
client;
|
|
25
|
+
constructor(client) {
|
|
26
|
+
this.client = client;
|
|
27
|
+
}
|
|
28
|
+
async review(step, evidence, executorResult, opts) {
|
|
29
|
+
const evidenceBlock = evidence
|
|
30
|
+
.map((e) => e.topArtifact
|
|
31
|
+
? // topArtifact is already a relevance-oriented, bounded extract.
|
|
32
|
+
`- ${e.ref}: closest artifact →\n${e.topArtifact}`
|
|
33
|
+
: `- ${e.ref}: MISSING (no artifact found)`)
|
|
34
|
+
.join('\n');
|
|
35
|
+
const res = await this.client.send([
|
|
36
|
+
{ role: 'system', content: appendHint(REVIEWER_SYSTEM, opts.hint) },
|
|
37
|
+
{
|
|
38
|
+
role: 'user',
|
|
39
|
+
content: `Step: ${step.name}\nIntent: ${step.instructions}\n` +
|
|
40
|
+
`Evidence:\n${evidenceBlock || '(none)'}\n` +
|
|
41
|
+
`Executor result:\n${executorResult}`,
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
opts.logUsage?.('reviewer', res.usage);
|
|
45
|
+
if (res.kind !== 'content') {
|
|
46
|
+
// Provider/transport error → JUDGE failure (the verdict is unknown), NOT a
|
|
47
|
+
// step failure.
|
|
48
|
+
return {
|
|
49
|
+
kind: 'judge-failure',
|
|
50
|
+
reason: `reviewer error: ${res.kind === 'error' ? res.error : res.kind}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return parseReview(res.content, opts.maxDigestChars ?? 500);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Parse a reviewer reply into a ReviewResult. A well-formed verdict (any of
|
|
57
|
+
* ok/exists/partial/failed) is an `outcome`; ok/exists/partial with EMPTY approved
|
|
58
|
+
* is coerced to a `failed` outcome (contradictory → replan, not abort). Only a
|
|
59
|
+
* truly unusable reply — unparsable JSON or missing/invalid status — is a
|
|
60
|
+
* `judge-failure` (re-ask within budget, then degrade to a failed step). */
|
|
61
|
+
export function parseReview(content, maxDigestChars = 500) {
|
|
62
|
+
const json = extractJsonObject(content);
|
|
63
|
+
if (json === null)
|
|
64
|
+
return { kind: 'judge-failure', reason: 'unparsable reviewer reply' };
|
|
65
|
+
try {
|
|
66
|
+
const o = JSON.parse(json);
|
|
67
|
+
const status = o.status;
|
|
68
|
+
const approved = typeof o.approved === 'string' ? o.approved : '';
|
|
69
|
+
const remainder = typeof o.remainder === 'string' ? o.remainder : '';
|
|
70
|
+
const note = typeof o.note === 'string' ? o.note : '';
|
|
71
|
+
const rawDigest = typeof o.digest === 'string' ? o.digest : '';
|
|
72
|
+
if (status !== 'ok' &&
|
|
73
|
+
status !== 'exists' &&
|
|
74
|
+
status !== 'failed' &&
|
|
75
|
+
status !== 'partial') {
|
|
76
|
+
return { kind: 'judge-failure', reason: 'missing/invalid status' };
|
|
77
|
+
}
|
|
78
|
+
// Digest is REQUIRED on every settle (it is the planner's board content). A
|
|
79
|
+
// missing/empty digest is a judge-failure (re-ask), distinct from a real
|
|
80
|
+
// verdict. Bound it defensively (the full result is in RAG regardless).
|
|
81
|
+
if (rawDigest.trim().length === 0) {
|
|
82
|
+
return { kind: 'judge-failure', reason: 'missing digest' };
|
|
83
|
+
}
|
|
84
|
+
const digest = rawDigest.slice(0, maxDigestChars);
|
|
85
|
+
if ((status === 'ok' || status === 'exists' || status === 'partial') &&
|
|
86
|
+
approved.length === 0) {
|
|
87
|
+
const coercedNote = note
|
|
88
|
+
? `${note} [coerced: reviewer returned ${status} with empty approved]`
|
|
89
|
+
: `reviewer returned ${status} with empty approved`;
|
|
90
|
+
return {
|
|
91
|
+
kind: 'outcome',
|
|
92
|
+
outcome: {
|
|
93
|
+
status: 'failed',
|
|
94
|
+
approved: '',
|
|
95
|
+
remainder: remainder || approved,
|
|
96
|
+
note: coercedNote,
|
|
97
|
+
digest: (note || coercedNote).slice(0, maxDigestChars),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (status === 'partial' && remainder.trim().length === 0) {
|
|
102
|
+
return {
|
|
103
|
+
kind: 'outcome',
|
|
104
|
+
outcome: { status: 'ok', approved, remainder: '', note, digest },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
kind: 'outcome',
|
|
109
|
+
outcome: { status, approved, remainder, note, digest },
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return { kind: 'judge-failure', reason: 'unparsable reviewer reply' };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=reviewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewer.js","sourceRoot":"","sources":["../../../src/smart-agent/controller/reviewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { KnowledgeBackend } from '@mcp-abap-adt/llm-agent-libs';
|
|
2
|
+
import type { SessionBundle } from './types.js';
|
|
3
|
+
/** Injectable runId minter (matches the existing id-minter pattern); tests pass a
|
|
4
|
+
* deterministic counter. Default is time+random based. */
|
|
5
|
+
export type RunIdMinter = () => string;
|
|
6
|
+
/** Canonical identity fingerprint of a request: a hash of the NORMALIZED text
|
|
7
|
+
* (trimmed, internal whitespace collapsed). Used only for identity comparison —
|
|
8
|
+
* the verbatim request is kept separately for the finalizer. */
|
|
9
|
+
export declare function fingerprintRequest(request: string): string;
|
|
10
|
+
export type TerminalOutcome = {
|
|
11
|
+
kind: 'success';
|
|
12
|
+
answer: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'error';
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
/** Persist a terminal outcome keyed by runId with a TTL. Written into the same
|
|
18
|
+
* KnowledgeBackend as the bundle but under a distinct artifactType so it
|
|
19
|
+
* survives the next run's bundle reset (the TTL promise). `nowIso` is passed so
|
|
20
|
+
* the caller controls time. */
|
|
21
|
+
export declare function writeTerminal(be: KnowledgeBackend, sessionId: string, runId: string, terminalOutcome: TerminalOutcome, ttlMs: number, nowIso: string): Promise<void>;
|
|
22
|
+
/** Read the latest non-expired terminal outcome for runId, or undefined. */
|
|
23
|
+
export declare function readTerminal(be: KnowledgeBackend, sessionId: string, runId: string, nowIso: string): Promise<TerminalOutcome | undefined>;
|
|
24
|
+
/** The runIds whose terminal entries are expired as of nowIso (backends without
|
|
25
|
+
* delete simply ignore stale rows on read). */
|
|
26
|
+
export declare function gcTerminal(be: KnowledgeBackend, sessionId: string, nowIso: string): Promise<string[]>;
|
|
27
|
+
export type Classification = {
|
|
28
|
+
kind: 'fresh';
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'resume';
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'replay';
|
|
33
|
+
runId: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'not-found';
|
|
36
|
+
};
|
|
37
|
+
export interface ClassifyInput {
|
|
38
|
+
bundle: SessionBundle;
|
|
39
|
+
incomingRequest: string;
|
|
40
|
+
/** Explicit idempotency key / runId supplied by the caller (if any). */
|
|
41
|
+
explicitKey?: string;
|
|
42
|
+
/** True when the consumer set the newRun flag for THIS request. */
|
|
43
|
+
newRun?: boolean;
|
|
44
|
+
/** Whether `explicitKey` (or, for fingerprint matches, the current bundle's
|
|
45
|
+
* runId) has a non-expired terminal-store entry. */
|
|
46
|
+
terminalExists: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Strict ordered request classification. First matching branch wins. */
|
|
49
|
+
export declare function classifyRequest(input: ClassifyInput): Classification;
|
|
50
|
+
//# sourceMappingURL=run-scope.d.ts.map
|