myshell-tools 1.0.0 → 2.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/CHANGELOG.md +44 -69
- package/LICENSE +21 -21
- package/README.md +178 -318
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +130 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cost.d.ts +36 -0
- package/dist/commands/cost.js +103 -0
- package/dist/commands/cost.js.map +1 -0
- package/dist/commands/doctor.d.ts +36 -0
- package/dist/commands/doctor.js +115 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/login.d.ts +20 -0
- package/dist/commands/login.js +60 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/core/assess.d.ts +25 -0
- package/dist/core/assess.js +142 -0
- package/dist/core/assess.js.map +1 -0
- package/dist/core/classify.d.ts +19 -0
- package/dist/core/classify.js +80 -0
- package/dist/core/classify.js.map +1 -0
- package/dist/core/escalate.d.ts +32 -0
- package/dist/core/escalate.js +57 -0
- package/dist/core/escalate.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/orchestrate.d.ts +42 -0
- package/dist/core/orchestrate.js +439 -0
- package/dist/core/orchestrate.js.map +1 -0
- package/dist/core/policy.d.ts +9 -0
- package/dist/core/policy.js +27 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/prompt.d.ts +26 -0
- package/dist/core/prompt.js +125 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/review.d.ts +46 -0
- package/dist/core/review.js +148 -0
- package/dist/core/review.js.map +1 -0
- package/dist/core/route.d.ts +28 -0
- package/dist/core/route.js +52 -0
- package/dist/core/route.js.map +1 -0
- package/dist/core/types.d.ts +141 -0
- package/dist/core/types.js +14 -0
- package/dist/core/types.js.map +1 -0
- package/dist/infra/atomic.d.ts +53 -0
- package/dist/infra/atomic.js +171 -0
- package/dist/infra/atomic.js.map +1 -0
- package/dist/infra/clock.d.ts +9 -0
- package/dist/infra/clock.js +15 -0
- package/dist/infra/clock.js.map +1 -0
- package/dist/infra/index.d.ts +9 -0
- package/dist/infra/index.js +7 -0
- package/dist/infra/index.js.map +1 -0
- package/dist/infra/ledger.d.ts +49 -0
- package/dist/infra/ledger.js +90 -0
- package/dist/infra/ledger.js.map +1 -0
- package/dist/infra/paths.d.ts +28 -0
- package/dist/infra/paths.js +38 -0
- package/dist/infra/paths.js.map +1 -0
- package/dist/infra/pricing.d.ts +47 -0
- package/dist/infra/pricing.js +151 -0
- package/dist/infra/pricing.js.map +1 -0
- package/dist/infra/session.d.ts +28 -0
- package/dist/infra/session.js +61 -0
- package/dist/infra/session.js.map +1 -0
- package/dist/interface/render.d.ts +27 -0
- package/dist/interface/render.js +134 -0
- package/dist/interface/render.js.map +1 -0
- package/dist/interface/repl.d.ts +23 -0
- package/dist/interface/repl.js +90 -0
- package/dist/interface/repl.js.map +1 -0
- package/dist/interface/run.d.ts +20 -0
- package/dist/interface/run.js +31 -0
- package/dist/interface/run.js.map +1 -0
- package/dist/providers/claude-parse.d.ts +24 -0
- package/dist/providers/claude-parse.js +113 -0
- package/dist/providers/claude-parse.js.map +1 -0
- package/dist/providers/claude.d.ts +45 -0
- package/dist/providers/claude.js +122 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/codex-parse.d.ts +32 -0
- package/dist/providers/codex-parse.js +145 -0
- package/dist/providers/codex-parse.js.map +1 -0
- package/dist/providers/codex.d.ts +44 -0
- package/dist/providers/codex.js +124 -0
- package/dist/providers/codex.js.map +1 -0
- package/dist/providers/detect.d.ts +49 -0
- package/dist/providers/detect.js +125 -0
- package/dist/providers/detect.js.map +1 -0
- package/dist/providers/errors.d.ts +49 -0
- package/dist/providers/errors.js +189 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/port.d.ts +74 -0
- package/dist/providers/port.js +16 -0
- package/dist/providers/port.js.map +1 -0
- package/dist/providers/registry.d.ts +21 -0
- package/dist/providers/registry.js +34 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/ui/banner.d.ts +19 -0
- package/dist/ui/banner.js +32 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/spinner.d.ts +27 -0
- package/dist/ui/spinner.js +67 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/theme.d.ts +32 -0
- package/dist/ui/theme.js +56 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +55 -49
- package/data/orchestrator.json +0 -113
- package/src/auth/recovery.mjs +0 -328
- package/src/auth/refresh.mjs +0 -373
- package/src/chef.mjs +0 -348
- package/src/cli/doctor.mjs +0 -568
- package/src/cli/reset.mjs +0 -447
- package/src/cli/status.mjs +0 -379
- package/src/cli.mjs +0 -429
- package/src/commands/doctor.mjs +0 -375
- package/src/commands/help.mjs +0 -324
- package/src/commands/status.mjs +0 -331
- package/src/monitor/health.mjs +0 -486
- package/src/monitor/performance.mjs +0 -442
- package/src/monitor/report.mjs +0 -535
- package/src/orchestrator/classify.mjs +0 -391
- package/src/orchestrator/confidence.mjs +0 -151
- package/src/orchestrator/handoffs.mjs +0 -231
- package/src/orchestrator/review.mjs +0 -222
- package/src/providers/balance.mjs +0 -201
- package/src/providers/claude.mjs +0 -236
- package/src/providers/codex.mjs +0 -255
- package/src/providers/detect.mjs +0 -185
- package/src/providers/errors.mjs +0 -373
- package/src/providers/select.mjs +0 -162
- package/src/repl-enhanced.mjs +0 -417
- package/src/repl.mjs +0 -321
- package/src/state/archive.mjs +0 -366
- package/src/state/atomic.mjs +0 -116
- package/src/state/cleanup.mjs +0 -440
- package/src/state/recovery.mjs +0 -461
- package/src/state/session.mjs +0 -147
- package/src/ui/errors.mjs +0 -456
- package/src/ui/formatter.mjs +0 -327
- package/src/ui/icons.mjs +0 -318
- package/src/ui/progress.mjs +0 -468
- package/templates/prompts/confidence-format.txt +0 -14
- package/templates/prompts/ic-with-feedback.txt +0 -41
- package/templates/prompts/ic.txt +0 -13
- package/templates/prompts/manager-review.txt +0 -40
- package/templates/prompts/manager.txt +0 -14
- package/templates/prompts/worker.txt +0 -12
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/orchestrate.ts — the bounded escalation + review loop.
|
|
3
|
+
*
|
|
4
|
+
* Implements the Phase-2 multi-tier loop:
|
|
5
|
+
* classify → route → run IC → (optionally) cross-vendor review → assess →
|
|
6
|
+
* escalate/retry/accept → final
|
|
7
|
+
*
|
|
8
|
+
* Control-flow overview:
|
|
9
|
+
* 1. Classify the task.
|
|
10
|
+
* 2. If no providers → notice(error) + final(false); return.
|
|
11
|
+
* 3. Append user session entry once.
|
|
12
|
+
* 4. Loop (≤ maxAttempts):
|
|
13
|
+
* a. Route to provider+model for currentTier.
|
|
14
|
+
* b. Yield tier-start → stream provider events → yield tier-done.
|
|
15
|
+
* c. Provider failure → escalate to manager (or break if already there).
|
|
16
|
+
* d. If IC tier + shouldReview(classification, assessment):
|
|
17
|
+
* run cross-vendor reviewer at manager tier.
|
|
18
|
+
* approve → accept; revise → retry IC with notes; escalate → escalate tier.
|
|
19
|
+
* e. Low-confidence / escalate signal → nextTierUp → continue.
|
|
20
|
+
* f. All good → yield final(success:true); return.
|
|
21
|
+
* 5. Loop exhausted or broke on failure → yield final(success:false).
|
|
22
|
+
*
|
|
23
|
+
* Purity rules (enforced by test/arch/guards.test.ts):
|
|
24
|
+
* - No imports of fs / path / child_process
|
|
25
|
+
* - No console.* calls
|
|
26
|
+
* - No Date.now() / Math.random() / new Date() — use deps.clock
|
|
27
|
+
* - No process.exit() — only src/cli.ts may terminate the process
|
|
28
|
+
*/
|
|
29
|
+
import { classify } from './classify.js';
|
|
30
|
+
import { route } from './route.js';
|
|
31
|
+
import { buildPrompt } from './prompt.js';
|
|
32
|
+
import { assess } from './assess.js';
|
|
33
|
+
import { getModelPricing, calculateCost } from '../infra/pricing.js';
|
|
34
|
+
import { nextTierUp, pickReviewer } from './escalate.js';
|
|
35
|
+
import { buildReviewPrompt, parseReviewVerdict } from './review.js';
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Pure helper: should this IC output be cross-vendor reviewed?
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
function shouldReview(classification, assessment) {
|
|
40
|
+
return (classification.risk === 'high' ||
|
|
41
|
+
classification.risk === 'critical' ||
|
|
42
|
+
assessment.needsReview === true);
|
|
43
|
+
}
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Public API
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
/**
|
|
48
|
+
* Orchestrate a task through the bounded escalation + review loop.
|
|
49
|
+
*
|
|
50
|
+
* Yields a sequence of {@link CoreEvent} objects.
|
|
51
|
+
* The interface/render layer drives the generator and surfaces events to
|
|
52
|
+
* the user.
|
|
53
|
+
*
|
|
54
|
+
* @param task - The raw user task description.
|
|
55
|
+
* @param deps - Injected dependencies (providers, clock, session, ledger, policy, …).
|
|
56
|
+
* @param signal - AbortSignal; when aborted the generator stops and yields a
|
|
57
|
+
* notice(warn, 'cancelled') followed by final(success:false).
|
|
58
|
+
*/
|
|
59
|
+
export async function* orchestrate(task, deps, signal) {
|
|
60
|
+
// -------------------------------------------------------------------------
|
|
61
|
+
// (a) Classify the task
|
|
62
|
+
// -------------------------------------------------------------------------
|
|
63
|
+
const classification = classify(task);
|
|
64
|
+
yield { type: 'classified', classification };
|
|
65
|
+
// -------------------------------------------------------------------------
|
|
66
|
+
// (b) Resolve available providers
|
|
67
|
+
// -------------------------------------------------------------------------
|
|
68
|
+
const available = Object.keys(deps.providers).filter((id) => deps.providers[id] !== undefined);
|
|
69
|
+
// -------------------------------------------------------------------------
|
|
70
|
+
// (c) No providers path
|
|
71
|
+
// -------------------------------------------------------------------------
|
|
72
|
+
if (available.length === 0) {
|
|
73
|
+
yield {
|
|
74
|
+
type: 'notice',
|
|
75
|
+
level: 'error',
|
|
76
|
+
message: 'No providers are available. Install and authenticate at least one provider ' +
|
|
77
|
+
'(claude or codex) and try again.',
|
|
78
|
+
};
|
|
79
|
+
yield {
|
|
80
|
+
type: 'final',
|
|
81
|
+
success: false,
|
|
82
|
+
output: 'No providers available.',
|
|
83
|
+
tier: classification.tier,
|
|
84
|
+
totalCostUsd: 0,
|
|
85
|
+
sessionId: deps.session.id,
|
|
86
|
+
attempts: 0,
|
|
87
|
+
};
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// -------------------------------------------------------------------------
|
|
91
|
+
// (d) Append user message to session once (before any tier run)
|
|
92
|
+
// -------------------------------------------------------------------------
|
|
93
|
+
await deps.session.append({
|
|
94
|
+
timestamp: deps.clock.isoNow(),
|
|
95
|
+
role: 'user',
|
|
96
|
+
content: task,
|
|
97
|
+
});
|
|
98
|
+
// -------------------------------------------------------------------------
|
|
99
|
+
// (e) Loop state
|
|
100
|
+
// -------------------------------------------------------------------------
|
|
101
|
+
let currentTier = classification.tier;
|
|
102
|
+
let managerNotes;
|
|
103
|
+
let attempts = 0;
|
|
104
|
+
let totalCostUsd = 0;
|
|
105
|
+
let lastOutput = '';
|
|
106
|
+
// -------------------------------------------------------------------------
|
|
107
|
+
// (f) Main orchestration loop
|
|
108
|
+
// -------------------------------------------------------------------------
|
|
109
|
+
mainLoop: while (attempts < deps.policy.maxAttempts) {
|
|
110
|
+
attempts++;
|
|
111
|
+
// --- Route for current tier ---
|
|
112
|
+
const decision = route(currentTier, available, deps.policy);
|
|
113
|
+
const provider = deps.providers[decision.provider];
|
|
114
|
+
if (provider === undefined) {
|
|
115
|
+
yield {
|
|
116
|
+
type: 'notice',
|
|
117
|
+
level: 'error',
|
|
118
|
+
message: `Provider "${decision.provider}" was selected by route() but is not present in deps.providers.`,
|
|
119
|
+
};
|
|
120
|
+
break mainLoop;
|
|
121
|
+
}
|
|
122
|
+
// --- Build prompt (with optional reviewer feedback on IC retry) ---
|
|
123
|
+
const prompt = currentTier === 'ic' && managerNotes !== undefined
|
|
124
|
+
? buildPrompt(currentTier, task, managerNotes)
|
|
125
|
+
: buildPrompt(currentTier, task);
|
|
126
|
+
// --- Yield tier-start ---
|
|
127
|
+
yield {
|
|
128
|
+
type: 'tier-start',
|
|
129
|
+
tier: decision.tier,
|
|
130
|
+
provider: decision.provider,
|
|
131
|
+
model: decision.model,
|
|
132
|
+
attempt: attempts,
|
|
133
|
+
};
|
|
134
|
+
// --- Build request and record start time ---
|
|
135
|
+
const req = {
|
|
136
|
+
model: decision.model,
|
|
137
|
+
prompt,
|
|
138
|
+
cwd: deps.cwd,
|
|
139
|
+
sandbox: deps.sandbox,
|
|
140
|
+
timeoutMs: deps.timeoutMs,
|
|
141
|
+
};
|
|
142
|
+
const start = deps.clock.now();
|
|
143
|
+
let finalText;
|
|
144
|
+
let errored;
|
|
145
|
+
let usage;
|
|
146
|
+
let providerCostUsd;
|
|
147
|
+
// Check abort before entering the stream
|
|
148
|
+
if (signal.aborted) {
|
|
149
|
+
yield { type: 'notice', level: 'warn', message: 'cancelled' };
|
|
150
|
+
yield {
|
|
151
|
+
type: 'final',
|
|
152
|
+
success: false,
|
|
153
|
+
output: 'Task was cancelled before it started.',
|
|
154
|
+
tier: decision.tier,
|
|
155
|
+
totalCostUsd,
|
|
156
|
+
sessionId: deps.session.id,
|
|
157
|
+
attempts,
|
|
158
|
+
};
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// --- Stream provider events ---
|
|
162
|
+
for await (const ev of provider.run(req, signal)) {
|
|
163
|
+
yield { type: 'provider-event', tier: decision.tier, event: ev };
|
|
164
|
+
if (ev.type === 'done') {
|
|
165
|
+
finalText = ev.text;
|
|
166
|
+
if (ev.usage !== undefined && usage === undefined) {
|
|
167
|
+
usage = ev.usage;
|
|
168
|
+
}
|
|
169
|
+
if (ev.costUsd !== undefined) {
|
|
170
|
+
providerCostUsd = ev.costUsd;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (ev.type === 'error') {
|
|
174
|
+
errored = ev.error;
|
|
175
|
+
}
|
|
176
|
+
else if (ev.type === 'usage' && usage === undefined) {
|
|
177
|
+
usage = ev.usage;
|
|
178
|
+
}
|
|
179
|
+
if (signal.aborted) {
|
|
180
|
+
yield { type: 'notice', level: 'warn', message: 'cancelled' };
|
|
181
|
+
yield {
|
|
182
|
+
type: 'final',
|
|
183
|
+
success: false,
|
|
184
|
+
output: 'Task was cancelled.',
|
|
185
|
+
tier: decision.tier,
|
|
186
|
+
totalCostUsd,
|
|
187
|
+
sessionId: deps.session.id,
|
|
188
|
+
attempts,
|
|
189
|
+
};
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// --- Compute duration + cost ---
|
|
194
|
+
const durationMs = deps.clock.now() - start;
|
|
195
|
+
const success = errored == null;
|
|
196
|
+
const pricing = getModelPricing(decision.provider, decision.model);
|
|
197
|
+
const usd = providerCostUsd ??
|
|
198
|
+
(usage !== undefined && pricing !== undefined
|
|
199
|
+
? calculateCost(usage.inputTokens, usage.outputTokens, pricing)
|
|
200
|
+
: 0);
|
|
201
|
+
totalCostUsd += usd;
|
|
202
|
+
// --- Assess output ---
|
|
203
|
+
const assessment = assess(finalText ?? '');
|
|
204
|
+
// --- Record in ledger ---
|
|
205
|
+
await deps.ledger.record({
|
|
206
|
+
timestamp: deps.clock.isoNow(),
|
|
207
|
+
sessionId: deps.session.id,
|
|
208
|
+
taskId: deps.clock.uuid(),
|
|
209
|
+
provider: decision.provider,
|
|
210
|
+
model: decision.model,
|
|
211
|
+
tier: decision.tier,
|
|
212
|
+
inputTokens: usage?.inputTokens ?? 0,
|
|
213
|
+
outputTokens: usage?.outputTokens ?? 0,
|
|
214
|
+
cachedInputTokens: usage?.cachedInputTokens ?? 0,
|
|
215
|
+
usd,
|
|
216
|
+
durationMs,
|
|
217
|
+
success,
|
|
218
|
+
});
|
|
219
|
+
// --- Append assistant session entry ---
|
|
220
|
+
await deps.session.append({
|
|
221
|
+
timestamp: deps.clock.isoNow(),
|
|
222
|
+
role: 'assistant',
|
|
223
|
+
content: finalText ?? (errored?.message ?? ''),
|
|
224
|
+
tier: decision.tier,
|
|
225
|
+
provider: decision.provider,
|
|
226
|
+
model: decision.model,
|
|
227
|
+
confidence: assessment.confidence,
|
|
228
|
+
costUsd: usd,
|
|
229
|
+
durationMs,
|
|
230
|
+
});
|
|
231
|
+
// --- Yield tier-done ---
|
|
232
|
+
yield {
|
|
233
|
+
type: 'tier-done',
|
|
234
|
+
tier: decision.tier,
|
|
235
|
+
success,
|
|
236
|
+
confidence: assessment.confidence,
|
|
237
|
+
costUsd: usd,
|
|
238
|
+
durationMs,
|
|
239
|
+
};
|
|
240
|
+
lastOutput = finalText ?? (errored?.message ?? '');
|
|
241
|
+
// -----------------------------------------------------------------------
|
|
242
|
+
// Decision tree
|
|
243
|
+
// -----------------------------------------------------------------------
|
|
244
|
+
// 1) Provider failure → escalate to manager (or fail if already there)
|
|
245
|
+
if (!success) {
|
|
246
|
+
if (currentTier !== 'manager') {
|
|
247
|
+
yield { type: 'escalate', from: currentTier, to: 'manager', reason: 'execution failure' };
|
|
248
|
+
currentTier = 'manager';
|
|
249
|
+
continue mainLoop;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
break mainLoop; // already at manager; emit failing final below
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// 2) Cross-vendor review for IC work on high/critical risk or needsReview
|
|
256
|
+
if (currentTier === 'ic' && shouldReview(classification, assessment)) {
|
|
257
|
+
const reviewerId = pickReviewer(available, decision.provider);
|
|
258
|
+
const reviewerProvider = reviewerId === null ? undefined : deps.providers[reviewerId];
|
|
259
|
+
if (reviewerId !== null && reviewerProvider !== undefined) {
|
|
260
|
+
const sameVendor = reviewerId === decision.provider;
|
|
261
|
+
yield {
|
|
262
|
+
type: 'notice',
|
|
263
|
+
level: 'info',
|
|
264
|
+
message: `Review by ${reviewerId} (${sameVendor ? 'same vendor' : 'cross-vendor'})`,
|
|
265
|
+
};
|
|
266
|
+
// Route reviewer at manager tier
|
|
267
|
+
const reviewDecision = route('manager', [reviewerId], deps.policy);
|
|
268
|
+
const reviewPrompt = buildReviewPrompt(task, lastOutput);
|
|
269
|
+
// Yield tier-start for review run
|
|
270
|
+
yield {
|
|
271
|
+
type: 'tier-start',
|
|
272
|
+
tier: 'manager',
|
|
273
|
+
provider: reviewerId,
|
|
274
|
+
model: reviewDecision.model,
|
|
275
|
+
attempt: attempts,
|
|
276
|
+
};
|
|
277
|
+
const reviewReq = {
|
|
278
|
+
model: reviewDecision.model,
|
|
279
|
+
prompt: reviewPrompt,
|
|
280
|
+
cwd: deps.cwd,
|
|
281
|
+
sandbox: deps.sandbox,
|
|
282
|
+
timeoutMs: deps.timeoutMs,
|
|
283
|
+
};
|
|
284
|
+
const reviewStart = deps.clock.now();
|
|
285
|
+
let reviewText;
|
|
286
|
+
let reviewErrored;
|
|
287
|
+
let reviewUsage;
|
|
288
|
+
let reviewProviderCostUsd;
|
|
289
|
+
// Check abort before reviewer streaming
|
|
290
|
+
if (signal.aborted) {
|
|
291
|
+
yield { type: 'notice', level: 'warn', message: 'cancelled' };
|
|
292
|
+
yield {
|
|
293
|
+
type: 'final',
|
|
294
|
+
success: false,
|
|
295
|
+
output: 'Task was cancelled.',
|
|
296
|
+
tier: currentTier,
|
|
297
|
+
totalCostUsd,
|
|
298
|
+
sessionId: deps.session.id,
|
|
299
|
+
attempts,
|
|
300
|
+
};
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
for await (const rev of reviewerProvider.run(reviewReq, signal)) {
|
|
304
|
+
yield { type: 'provider-event', tier: 'manager', event: rev };
|
|
305
|
+
if (rev.type === 'done') {
|
|
306
|
+
reviewText = rev.text;
|
|
307
|
+
if (rev.usage !== undefined && reviewUsage === undefined) {
|
|
308
|
+
reviewUsage = rev.usage;
|
|
309
|
+
}
|
|
310
|
+
if (rev.costUsd !== undefined) {
|
|
311
|
+
reviewProviderCostUsd = rev.costUsd;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else if (rev.type === 'error') {
|
|
315
|
+
reviewErrored = rev.error;
|
|
316
|
+
}
|
|
317
|
+
else if (rev.type === 'usage' && reviewUsage === undefined) {
|
|
318
|
+
reviewUsage = rev.usage;
|
|
319
|
+
}
|
|
320
|
+
if (signal.aborted) {
|
|
321
|
+
yield { type: 'notice', level: 'warn', message: 'cancelled' };
|
|
322
|
+
yield {
|
|
323
|
+
type: 'final',
|
|
324
|
+
success: false,
|
|
325
|
+
output: 'Task was cancelled.',
|
|
326
|
+
tier: currentTier,
|
|
327
|
+
totalCostUsd,
|
|
328
|
+
sessionId: deps.session.id,
|
|
329
|
+
attempts,
|
|
330
|
+
};
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const reviewDurationMs = deps.clock.now() - reviewStart;
|
|
335
|
+
const reviewSuccess = reviewErrored == null;
|
|
336
|
+
const reviewPricing = getModelPricing(reviewerId, reviewDecision.model);
|
|
337
|
+
const reviewUsd = reviewProviderCostUsd ??
|
|
338
|
+
(reviewUsage !== undefined && reviewPricing !== undefined
|
|
339
|
+
? calculateCost(reviewUsage.inputTokens, reviewUsage.outputTokens, reviewPricing)
|
|
340
|
+
: 0);
|
|
341
|
+
totalCostUsd += reviewUsd;
|
|
342
|
+
// Record reviewer run in ledger
|
|
343
|
+
await deps.ledger.record({
|
|
344
|
+
timestamp: deps.clock.isoNow(),
|
|
345
|
+
sessionId: deps.session.id,
|
|
346
|
+
taskId: deps.clock.uuid(),
|
|
347
|
+
provider: reviewerId,
|
|
348
|
+
model: reviewDecision.model,
|
|
349
|
+
tier: 'manager',
|
|
350
|
+
inputTokens: reviewUsage?.inputTokens ?? 0,
|
|
351
|
+
outputTokens: reviewUsage?.outputTokens ?? 0,
|
|
352
|
+
cachedInputTokens: reviewUsage?.cachedInputTokens ?? 0,
|
|
353
|
+
usd: reviewUsd,
|
|
354
|
+
durationMs: reviewDurationMs,
|
|
355
|
+
success: reviewSuccess,
|
|
356
|
+
});
|
|
357
|
+
// Yield tier-done for reviewer
|
|
358
|
+
yield {
|
|
359
|
+
type: 'tier-done',
|
|
360
|
+
tier: 'manager',
|
|
361
|
+
success: reviewSuccess,
|
|
362
|
+
confidence: null,
|
|
363
|
+
costUsd: reviewUsd,
|
|
364
|
+
durationMs: reviewDurationMs,
|
|
365
|
+
};
|
|
366
|
+
// Parse verdict and act on it
|
|
367
|
+
const verdict = parseReviewVerdict(reviewText ?? '');
|
|
368
|
+
yield {
|
|
369
|
+
type: 'notice',
|
|
370
|
+
level: 'info',
|
|
371
|
+
message: `Review verdict: ${verdict.verdict}`,
|
|
372
|
+
};
|
|
373
|
+
if (verdict.verdict === 'approve') {
|
|
374
|
+
yield {
|
|
375
|
+
type: 'final',
|
|
376
|
+
success: true,
|
|
377
|
+
output: lastOutput,
|
|
378
|
+
tier: currentTier,
|
|
379
|
+
totalCostUsd,
|
|
380
|
+
sessionId: deps.session.id,
|
|
381
|
+
attempts,
|
|
382
|
+
};
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (verdict.verdict === 'revise') {
|
|
386
|
+
// Retry IC with reviewer's notes; managerNotes is cleared after use
|
|
387
|
+
managerNotes = verdict.notes;
|
|
388
|
+
// Stay at 'ic' tier; loop continues
|
|
389
|
+
continue mainLoop;
|
|
390
|
+
}
|
|
391
|
+
// verdict === 'escalate'
|
|
392
|
+
yield { type: 'escalate', from: 'ic', to: 'manager', reason: 'reviewer escalation' };
|
|
393
|
+
currentTier = 'manager';
|
|
394
|
+
continue mainLoop;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// 3) Confidence-based escalation
|
|
398
|
+
const threshold = deps.policy.escalateBelowConfidence[classification.risk];
|
|
399
|
+
const needEsc = assessment.escalate ||
|
|
400
|
+
(assessment.confidence !== null && assessment.confidence < threshold);
|
|
401
|
+
const nextTier = nextTierUp(currentTier);
|
|
402
|
+
if (needEsc && nextTier !== null) {
|
|
403
|
+
const escalateReason = assessment.reason !== 'model provided no reason' &&
|
|
404
|
+
assessment.reason !== 'no confidence envelope'
|
|
405
|
+
? assessment.reason
|
|
406
|
+
: 'low confidence';
|
|
407
|
+
yield {
|
|
408
|
+
type: 'escalate',
|
|
409
|
+
from: currentTier,
|
|
410
|
+
to: nextTier,
|
|
411
|
+
reason: escalateReason,
|
|
412
|
+
};
|
|
413
|
+
currentTier = nextTier;
|
|
414
|
+
continue mainLoop;
|
|
415
|
+
}
|
|
416
|
+
// 4) Accept — everything checks out
|
|
417
|
+
yield {
|
|
418
|
+
type: 'final',
|
|
419
|
+
success: true,
|
|
420
|
+
output: lastOutput,
|
|
421
|
+
tier: currentTier,
|
|
422
|
+
totalCostUsd,
|
|
423
|
+
sessionId: deps.session.id,
|
|
424
|
+
attempts,
|
|
425
|
+
};
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
// Loop exhausted or broke out on failure
|
|
429
|
+
yield {
|
|
430
|
+
type: 'final',
|
|
431
|
+
success: false,
|
|
432
|
+
output: lastOutput,
|
|
433
|
+
tier: currentTier,
|
|
434
|
+
totalCostUsd,
|
|
435
|
+
sessionId: deps.session.id,
|
|
436
|
+
attempts,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
//# sourceMappingURL=orchestrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrate.js","sourceRoot":"","sources":["../../src/core/orchestrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/policy.ts — the single source of orchestration thresholds & routing
|
|
3
|
+
* preferences. All tunable numbers live here (typed by `Policy` in types.ts),
|
|
4
|
+
* never scattered as magic constants across the core.
|
|
5
|
+
*
|
|
6
|
+
* Pure data module: no I/O, no time, no randomness.
|
|
7
|
+
*/
|
|
8
|
+
import type { Policy } from './types.js';
|
|
9
|
+
export declare const DEFAULT_POLICY: Policy;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/policy.ts — the single source of orchestration thresholds & routing
|
|
3
|
+
* preferences. All tunable numbers live here (typed by `Policy` in types.ts),
|
|
4
|
+
* never scattered as magic constants across the core.
|
|
5
|
+
*
|
|
6
|
+
* Pure data module: no I/O, no time, no randomness.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_POLICY = {
|
|
9
|
+
maxAttempts: 3,
|
|
10
|
+
// Higher-risk work demands higher confidence before we accept it; below the
|
|
11
|
+
// threshold we escalate to a higher tier (or, later, a cross-vendor review).
|
|
12
|
+
escalateBelowConfidence: {
|
|
13
|
+
low: 0.4,
|
|
14
|
+
medium: 0.5,
|
|
15
|
+
high: 0.7,
|
|
16
|
+
critical: 0.8,
|
|
17
|
+
},
|
|
18
|
+
// Provider preference per tier. route() picks the first available provider in
|
|
19
|
+
// this order that has a model for the tier; otherwise it falls back to the
|
|
20
|
+
// cheapest available model for that tier (via pricing.getCheapestForTier).
|
|
21
|
+
providerOrderByTier: {
|
|
22
|
+
worker: ['claude', 'codex'],
|
|
23
|
+
ic: ['claude', 'codex'],
|
|
24
|
+
manager: ['claude', 'codex'],
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/core/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,WAAW,EAAE,CAAC;IAEd,4EAA4E;IAC5E,6EAA6E;IAC7E,uBAAuB,EAAE;QACvB,GAAG,EAAE,GAAG;QACR,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,GAAG;KACd;IAED,8EAA8E;IAC9E,2EAA2E;IAC3E,2EAA2E;IAC3E,mBAAmB,EAAE;QACnB,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC7B;CACF,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/prompt.ts — typed, tier-specific prompt builders.
|
|
3
|
+
*
|
|
4
|
+
* Each tier gets a professional role prompt that instructs the model to perform
|
|
5
|
+
* real work and end its response with a structured JSON confidence envelope on
|
|
6
|
+
* its own line. The envelope is the only source of confidence data — no keyword
|
|
7
|
+
* heuristics, no fabricated numbers.
|
|
8
|
+
*
|
|
9
|
+
* Pure module: no I/O, no time, no randomness.
|
|
10
|
+
*/
|
|
11
|
+
import type { Tier } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Build the full prompt string to deliver to a model for the given tier.
|
|
14
|
+
*
|
|
15
|
+
* The system instructions are prepended to the raw task so the model receives
|
|
16
|
+
* role context before the user request.
|
|
17
|
+
*
|
|
18
|
+
* When `managerNotes` is provided (IC retry after a reviewer's `revise` verdict),
|
|
19
|
+
* the prompt is extended with a REVIEWER FEEDBACK section so the IC can address
|
|
20
|
+
* the specific feedback on its next attempt.
|
|
21
|
+
*
|
|
22
|
+
* @param tier - The orchestration tier that will handle the task.
|
|
23
|
+
* @param task - The raw user task description.
|
|
24
|
+
* @param managerNotes - Optional feedback from a cross-vendor reviewer to be addressed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildPrompt(tier: Tier, task: string, managerNotes?: string): string;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/core/prompt.ts — typed, tier-specific prompt builders.
|
|
3
|
+
*
|
|
4
|
+
* Each tier gets a professional role prompt that instructs the model to perform
|
|
5
|
+
* real work and end its response with a structured JSON confidence envelope on
|
|
6
|
+
* its own line. The envelope is the only source of confidence data — no keyword
|
|
7
|
+
* heuristics, no fabricated numbers.
|
|
8
|
+
*
|
|
9
|
+
* Pure module: no I/O, no time, no randomness.
|
|
10
|
+
*/
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Envelope schema (documented here for parser/prompt alignment)
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
//
|
|
15
|
+
// Every model response MUST end with exactly this JSON object on its own line:
|
|
16
|
+
//
|
|
17
|
+
// {"confidence": <0.0-1.0>, "escalate": <true|false>, "reason": "<string>", "needs_review": <true|false>}
|
|
18
|
+
//
|
|
19
|
+
// confidence : float [0,1] — the model's self-assessed probability of correctness
|
|
20
|
+
// escalate : true → the model requests a higher-tier pass
|
|
21
|
+
// reason : brief human-readable justification for the confidence / escalation
|
|
22
|
+
// needs_review: true → the model recommends cross-provider review
|
|
23
|
+
//
|
|
24
|
+
// The assess() function in assess.ts parses this envelope. If the envelope is
|
|
25
|
+
// absent or malformed, confidence is recorded as null (never fabricated).
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Tier role prompts
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const WORKER_SYSTEM = `\
|
|
30
|
+
You are a precise, efficient worker-tier assistant. Your role is to perform
|
|
31
|
+
well-scoped, read-oriented tasks: searching codebases, listing files, looking up
|
|
32
|
+
definitions, reading documentation, and answering factual questions about the
|
|
33
|
+
current project.
|
|
34
|
+
|
|
35
|
+
Guidelines:
|
|
36
|
+
- Be concise and direct. Do not pad responses with unnecessary explanation.
|
|
37
|
+
- Quote exact file paths, line numbers, and symbols when they are available.
|
|
38
|
+
- If the task requires writing or modifying files, note that explicitly and
|
|
39
|
+
recommend escalating to an IC-tier run.
|
|
40
|
+
- Do not speculate beyond what is directly observable in the project.
|
|
41
|
+
|
|
42
|
+
After completing the task, append EXACTLY the following JSON object on its own
|
|
43
|
+
line at the very end of your response (no trailing text after it):
|
|
44
|
+
{"confidence": <0.0-1.0>, "escalate": <true|false>, "reason": "<one sentence>", "needs_review": <true|false>}
|
|
45
|
+
|
|
46
|
+
Set confidence to your honest estimate of correctness (1.0 = certain, 0.0 = no
|
|
47
|
+
idea). Set escalate to true if the task requires a higher-tier model. Set
|
|
48
|
+
needs_review to true if you are uncertain and an independent check would help.`;
|
|
49
|
+
const IC_SYSTEM = `\
|
|
50
|
+
You are a skilled individual-contributor (IC) engineer. Your role is to
|
|
51
|
+
implement, refactor, debug, and explain code. You work directly in the project's
|
|
52
|
+
file tree, make targeted edits, run available tools, and produce clean,
|
|
53
|
+
well-reasoned output.
|
|
54
|
+
|
|
55
|
+
Guidelines:
|
|
56
|
+
- Read the relevant files before making changes.
|
|
57
|
+
- Make the smallest correct change that satisfies the task; avoid scope creep.
|
|
58
|
+
- If you modify files, describe each change with file path, what changed, and why.
|
|
59
|
+
- If you run commands (tests, builds), report the exact output.
|
|
60
|
+
- If the task involves high-stakes areas (auth, secrets, payments, deployments),
|
|
61
|
+
err on the side of caution and set needs_review to true.
|
|
62
|
+
|
|
63
|
+
After completing the task, append EXACTLY the following JSON object on its own
|
|
64
|
+
line at the very end of your response (no trailing text after it):
|
|
65
|
+
{"confidence": <0.0-1.0>, "escalate": <true|false>, "reason": "<one sentence>", "needs_review": <true|false>}
|
|
66
|
+
|
|
67
|
+
Set confidence to your honest estimate of correctness (1.0 = certain, 0.0 = no
|
|
68
|
+
idea). Set escalate to true if the task is beyond IC scope (e.g. requires
|
|
69
|
+
cross-cutting architectural decisions). Set needs_review to true if an
|
|
70
|
+
independent reviewer would meaningfully reduce risk.`;
|
|
71
|
+
const MANAGER_SYSTEM = `\
|
|
72
|
+
You are a senior-manager / staff-engineer-tier reviewer and architect. Your role
|
|
73
|
+
is to evaluate code, plans, and proposals; identify systemic risks; design
|
|
74
|
+
solutions; and produce authoritative recommendations.
|
|
75
|
+
|
|
76
|
+
Guidelines:
|
|
77
|
+
- Ground every finding in specific, file-anchored evidence (file path + line
|
|
78
|
+
range). Vague assertions are not acceptable.
|
|
79
|
+
- For security/threat-model reviews, enumerate each threat class, its severity
|
|
80
|
+
(Critical/High/Medium/Low), and a concrete mitigation.
|
|
81
|
+
- For architectural reviews, identify coupling, missing abstractions, and failure
|
|
82
|
+
modes — not just style issues.
|
|
83
|
+
- Produce a structured verdict with a clear APPROVE / REQUEST_CHANGES /
|
|
84
|
+
ESCALATE recommendation.
|
|
85
|
+
- If you identify a critical defect, set escalate to true and explain why
|
|
86
|
+
immediate attention is required.
|
|
87
|
+
|
|
88
|
+
After completing the review or plan, append EXACTLY the following JSON object on
|
|
89
|
+
its own line at the very end of your response (no trailing text after it):
|
|
90
|
+
{"confidence": <0.0-1.0>, "escalate": <true|false>, "reason": "<one sentence>", "needs_review": <true|false>}
|
|
91
|
+
|
|
92
|
+
Set confidence to your honest estimate that your analysis is complete and correct
|
|
93
|
+
(1.0 = certain, 0.0 = severely incomplete). Set escalate to true only if the
|
|
94
|
+
situation warrants immediate human or higher-tier intervention.`;
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Public API
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
/**
|
|
99
|
+
* Build the full prompt string to deliver to a model for the given tier.
|
|
100
|
+
*
|
|
101
|
+
* The system instructions are prepended to the raw task so the model receives
|
|
102
|
+
* role context before the user request.
|
|
103
|
+
*
|
|
104
|
+
* When `managerNotes` is provided (IC retry after a reviewer's `revise` verdict),
|
|
105
|
+
* the prompt is extended with a REVIEWER FEEDBACK section so the IC can address
|
|
106
|
+
* the specific feedback on its next attempt.
|
|
107
|
+
*
|
|
108
|
+
* @param tier - The orchestration tier that will handle the task.
|
|
109
|
+
* @param task - The raw user task description.
|
|
110
|
+
* @param managerNotes - Optional feedback from a cross-vendor reviewer to be addressed.
|
|
111
|
+
*/
|
|
112
|
+
export function buildPrompt(tier, task, managerNotes) {
|
|
113
|
+
const system = TIER_PROMPTS[tier];
|
|
114
|
+
let prompt = `${system}\n\n---\n\nTask:\n${task}`;
|
|
115
|
+
if (managerNotes !== undefined && managerNotes.trim().length > 0) {
|
|
116
|
+
prompt += `\n\nREVIEWER FEEDBACK:\n${managerNotes.trim()}\nAddress this specifically.`;
|
|
117
|
+
}
|
|
118
|
+
return prompt;
|
|
119
|
+
}
|
|
120
|
+
const TIER_PROMPTS = {
|
|
121
|
+
worker: WORKER_SYSTEM,
|
|
122
|
+
ic: IC_SYSTEM,
|
|
123
|
+
manager: MANAGER_SYSTEM,
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/core/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,8EAA8E;AAC9E,gEAAgE;AAChE,8EAA8E;AAC9E,EAAE;AACF,+EAA+E;AAC/E,EAAE;AACF,4GAA4G;AAC5G,EAAE;AACF,mFAAmF;AACnF,8DAA8D;AAC9D,mFAAmF;AACnF,mEAAmE;AACnE,EAAE;AACF,+EAA+E;AAC/E,0EAA0E;AAE1E,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;+EAmByD,CAAC;AAEhF,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;qDAqBmC,CAAC;AAEtD,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;gEAuByC,CAAC;AAEjE,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,IAAU,EAAE,IAAY,EAAE,YAAqB;IACzE,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,GAAG,MAAM,qBAAqB,IAAI,EAAE,CAAC;IAClD,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,2BAA2B,YAAY,CAAC,IAAI,EAAE,8BAA8B,CAAC;IACzF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,YAAY,GAAyB;IACzC,MAAM,EAAE,aAAa;IACrB,EAAE,EAAE,SAAS;IACb,OAAO,EAAE,cAAc;CACxB,CAAC"}
|