@yuaone/core 0.2.0 → 0.3.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/agent-loop.d.ts +40 -0
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +182 -4
- package/dist/agent-loop.js.map +1 -1
- package/dist/benchmark-runner.d.ts +141 -0
- package/dist/benchmark-runner.d.ts.map +1 -0
- package/dist/benchmark-runner.js +526 -0
- package/dist/benchmark-runner.js.map +1 -0
- package/dist/codebase-context.d.ts +49 -0
- package/dist/codebase-context.d.ts.map +1 -1
- package/dist/codebase-context.js +146 -0
- package/dist/codebase-context.js.map +1 -1
- package/dist/cost-optimizer.d.ts +159 -0
- package/dist/cost-optimizer.d.ts.map +1 -0
- package/dist/cost-optimizer.js +406 -0
- package/dist/cost-optimizer.js.map +1 -0
- package/dist/execution-policy-engine.d.ts +133 -0
- package/dist/execution-policy-engine.d.ts.map +1 -0
- package/dist/execution-policy-engine.js +367 -0
- package/dist/execution-policy-engine.js.map +1 -0
- package/dist/failure-recovery.d.ts +228 -0
- package/dist/failure-recovery.d.ts.map +1 -0
- package/dist/failure-recovery.js +664 -0
- package/dist/failure-recovery.js.map +1 -0
- package/dist/hierarchical-planner.d.ts +69 -1
- package/dist/hierarchical-planner.d.ts.map +1 -1
- package/dist/hierarchical-planner.js +117 -0
- package/dist/hierarchical-planner.js.map +1 -1
- package/dist/impact-analyzer.d.ts +92 -0
- package/dist/impact-analyzer.d.ts.map +1 -0
- package/dist/impact-analyzer.js +615 -0
- package/dist/impact-analyzer.js.map +1 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/world-state.d.ts +87 -0
- package/dist/world-state.d.ts.map +1 -0
- package/dist/world-state.js +435 -0
- package/dist/world-state.js.map +1 -0
- package/package.json +11 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-optimizer.d.ts","sourceRoot":"","sources":["../src/cost-optimizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cost-optimizer.ts — LLM Cost Optimization Module for YUAN Coding Agent
|
|
3
|
+
*
|
|
4
|
+
* Selects optimal models per task, predicts token usage,
|
|
5
|
+
* tracks costs, and enforces budget constraints.
|
|
6
|
+
*/
|
|
7
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
8
|
+
const DEFAULT_MODELS = [
|
|
9
|
+
{
|
|
10
|
+
tier: "cheap",
|
|
11
|
+
name: "claude-haiku-4-5",
|
|
12
|
+
inputCostPer1M: 0.80,
|
|
13
|
+
outputCostPer1M: 4.00,
|
|
14
|
+
maxContext: 200_000,
|
|
15
|
+
capabilities: ["simple", "classify", "grep"],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
tier: "cheap",
|
|
19
|
+
name: "gpt-4o-mini",
|
|
20
|
+
inputCostPer1M: 0.15,
|
|
21
|
+
outputCostPer1M: 0.60,
|
|
22
|
+
maxContext: 128_000,
|
|
23
|
+
capabilities: ["simple", "classify", "coding"],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
tier: "standard",
|
|
27
|
+
name: "claude-sonnet-4-6",
|
|
28
|
+
inputCostPer1M: 3.00,
|
|
29
|
+
outputCostPer1M: 15.00,
|
|
30
|
+
maxContext: 200_000,
|
|
31
|
+
capabilities: ["coding", "review", "test", "planning"],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
tier: "standard",
|
|
35
|
+
name: "gpt-4o",
|
|
36
|
+
inputCostPer1M: 2.50,
|
|
37
|
+
outputCostPer1M: 10.00,
|
|
38
|
+
maxContext: 128_000,
|
|
39
|
+
capabilities: ["coding", "review", "test"],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
tier: "premium",
|
|
43
|
+
name: "claude-opus-4-6",
|
|
44
|
+
inputCostPer1M: 15.00,
|
|
45
|
+
outputCostPer1M: 75.00,
|
|
46
|
+
maxContext: 200_000,
|
|
47
|
+
capabilities: ["coding", "planning", "debate", "review", "complex_refactor"],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
tier: "premium",
|
|
51
|
+
name: "o3",
|
|
52
|
+
inputCostPer1M: 10.00,
|
|
53
|
+
outputCostPer1M: 40.00,
|
|
54
|
+
maxContext: 200_000,
|
|
55
|
+
capabilities: ["coding", "planning", "debate", "complex_refactor"],
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
const DEFAULT_CONFIG = {
|
|
59
|
+
budgetUSD: 1.0,
|
|
60
|
+
defaultTier: "standard",
|
|
61
|
+
models: DEFAULT_MODELS,
|
|
62
|
+
enableAutoSelect: true,
|
|
63
|
+
costWarningThreshold: 0.8,
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Maps a task type to its base model tier.
|
|
67
|
+
* Tasks not listed here default to "standard".
|
|
68
|
+
*/
|
|
69
|
+
const TASK_TIER_MAP = {
|
|
70
|
+
classify: "cheap",
|
|
71
|
+
grep: "cheap",
|
|
72
|
+
simple_edit: "cheap",
|
|
73
|
+
coding: "standard",
|
|
74
|
+
review: "standard",
|
|
75
|
+
test: "standard",
|
|
76
|
+
planning: "premium",
|
|
77
|
+
debate: "premium",
|
|
78
|
+
complex_refactor: "premium",
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Output-to-input token ratio heuristics per task type.
|
|
82
|
+
* A ratio of 1.2 means the model is expected to produce
|
|
83
|
+
* 1.2x as many output tokens as input tokens.
|
|
84
|
+
*/
|
|
85
|
+
const TOKEN_OUTPUT_RATIO = {
|
|
86
|
+
classify: 0.3,
|
|
87
|
+
coding: 1.2,
|
|
88
|
+
planning: 2.0,
|
|
89
|
+
review: 0.8,
|
|
90
|
+
simple_edit: 0.5,
|
|
91
|
+
grep: 0.3,
|
|
92
|
+
test: 1.0,
|
|
93
|
+
debate: 1.5,
|
|
94
|
+
complex_refactor: 1.5,
|
|
95
|
+
};
|
|
96
|
+
const TIER_ORDER = ["cheap", "standard", "premium"];
|
|
97
|
+
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
98
|
+
function tierIndex(tier) {
|
|
99
|
+
return TIER_ORDER.indexOf(tier);
|
|
100
|
+
}
|
|
101
|
+
function clampTier(index) {
|
|
102
|
+
const clamped = Math.max(0, Math.min(index, TIER_ORDER.length - 1));
|
|
103
|
+
return TIER_ORDER[clamped];
|
|
104
|
+
}
|
|
105
|
+
function computeCost(profile, inputTokens, outputTokens) {
|
|
106
|
+
return ((inputTokens / 1_000_000) * profile.inputCostPer1M +
|
|
107
|
+
(outputTokens / 1_000_000) * profile.outputCostPer1M);
|
|
108
|
+
}
|
|
109
|
+
function emptyTierBucket() {
|
|
110
|
+
return { cost: 0, tokens: 0, calls: 0 };
|
|
111
|
+
}
|
|
112
|
+
// ─── CostOptimizer ──────────────────────────────────────────────────
|
|
113
|
+
export class CostOptimizer {
|
|
114
|
+
config;
|
|
115
|
+
records = [];
|
|
116
|
+
models = new Map();
|
|
117
|
+
constructor(config) {
|
|
118
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
119
|
+
// If caller provided models, use them; otherwise use defaults
|
|
120
|
+
if (config?.models) {
|
|
121
|
+
this.config.models = config.models;
|
|
122
|
+
}
|
|
123
|
+
for (const model of this.config.models) {
|
|
124
|
+
this.models.set(model.name, model);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// ── Model Selection ──────────────────────────────────────────────
|
|
128
|
+
/**
|
|
129
|
+
* Select the optimal model for a given task.
|
|
130
|
+
*
|
|
131
|
+
* Selection logic:
|
|
132
|
+
* 1. Determine base tier from taskType
|
|
133
|
+
* 2. Apply complexity modifier (trivial/simple → downgrade, complex/massive → upgrade)
|
|
134
|
+
* 3. Apply budget pressure (low budget → downgrade)
|
|
135
|
+
* 4. Pick the cheapest model in the resolved tier that has a matching capability
|
|
136
|
+
* 5. If auto-select is disabled, use defaultTier
|
|
137
|
+
*/
|
|
138
|
+
selectModel(taskType, complexity, estimatedTokens) {
|
|
139
|
+
let tier = this.config.enableAutoSelect
|
|
140
|
+
? this.resolveBaseTier(taskType)
|
|
141
|
+
: this.config.defaultTier;
|
|
142
|
+
// Complexity modifier
|
|
143
|
+
tier = this.applyComplexityModifier(tier, complexity);
|
|
144
|
+
// Budget pressure
|
|
145
|
+
tier = this.applyBudgetPressure(tier, taskType, estimatedTokens);
|
|
146
|
+
// Find best model in tier
|
|
147
|
+
return this.pickModelForTier(tier, taskType);
|
|
148
|
+
}
|
|
149
|
+
// ── Token Prediction ─────────────────────────────────────────────
|
|
150
|
+
/**
|
|
151
|
+
* Predict input and output token counts for a task.
|
|
152
|
+
*
|
|
153
|
+
* Input tokens are estimated as roughly `inputLength / 4` (avg chars per token).
|
|
154
|
+
* Output tokens use a task-specific multiplier on the input token count.
|
|
155
|
+
*/
|
|
156
|
+
predictTokens(taskType, inputLength) {
|
|
157
|
+
const inputTokens = Math.ceil(inputLength / 4);
|
|
158
|
+
const ratio = TOKEN_OUTPUT_RATIO[taskType] ?? 1.0;
|
|
159
|
+
const outputTokens = Math.ceil(inputTokens * ratio);
|
|
160
|
+
return { input: inputTokens, output: outputTokens };
|
|
161
|
+
}
|
|
162
|
+
// ── Cost Estimation ──────────────────────────────────────────────
|
|
163
|
+
/**
|
|
164
|
+
* Estimate the cost of a task before execution.
|
|
165
|
+
* Combines token prediction with model selection to produce a USD estimate.
|
|
166
|
+
*/
|
|
167
|
+
estimateCost(taskType, inputLength) {
|
|
168
|
+
const { input, output } = this.predictTokens(taskType, inputLength);
|
|
169
|
+
const model = this.selectModel(taskType, "normal", input);
|
|
170
|
+
const cost = computeCost(model, input, output);
|
|
171
|
+
return {
|
|
172
|
+
estimatedInputTokens: input,
|
|
173
|
+
estimatedOutputTokens: output,
|
|
174
|
+
estimatedCostUSD: Math.round(cost * 1_000_000) / 1_000_000,
|
|
175
|
+
model: model.name,
|
|
176
|
+
tier: model.tier,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// ── Usage Recording ──────────────────────────────────────────────
|
|
180
|
+
/**
|
|
181
|
+
* Record actual token usage after an LLM call completes.
|
|
182
|
+
* The cost is computed from the model's pricing profile.
|
|
183
|
+
* If the model is unknown, cost is recorded as 0.
|
|
184
|
+
*/
|
|
185
|
+
recordUsage(model, inputTokens, outputTokens, taskType) {
|
|
186
|
+
const profile = this.models.get(model);
|
|
187
|
+
const tier = profile?.tier ?? this.config.defaultTier;
|
|
188
|
+
const costUSD = profile ? computeCost(profile, inputTokens, outputTokens) : 0;
|
|
189
|
+
this.records.push({
|
|
190
|
+
model,
|
|
191
|
+
tier,
|
|
192
|
+
inputTokens,
|
|
193
|
+
outputTokens,
|
|
194
|
+
costUSD,
|
|
195
|
+
taskType,
|
|
196
|
+
timestamp: Date.now(),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// ── Summary ──────────────────────────────────────────────────────
|
|
200
|
+
/**
|
|
201
|
+
* Produce a summary of all costs recorded in this session.
|
|
202
|
+
*/
|
|
203
|
+
getSummary() {
|
|
204
|
+
const byModel = {};
|
|
205
|
+
const byTier = {
|
|
206
|
+
cheap: emptyTierBucket(),
|
|
207
|
+
standard: emptyTierBucket(),
|
|
208
|
+
premium: emptyTierBucket(),
|
|
209
|
+
};
|
|
210
|
+
let totalCostUSD = 0;
|
|
211
|
+
let totalInputTokens = 0;
|
|
212
|
+
let totalOutputTokens = 0;
|
|
213
|
+
for (const record of this.records) {
|
|
214
|
+
totalCostUSD += record.costUSD;
|
|
215
|
+
totalInputTokens += record.inputTokens;
|
|
216
|
+
totalOutputTokens += record.outputTokens;
|
|
217
|
+
// By model
|
|
218
|
+
if (!byModel[record.model]) {
|
|
219
|
+
byModel[record.model] = { cost: 0, tokens: 0, calls: 0 };
|
|
220
|
+
}
|
|
221
|
+
byModel[record.model].cost += record.costUSD;
|
|
222
|
+
byModel[record.model].tokens += record.inputTokens + record.outputTokens;
|
|
223
|
+
byModel[record.model].calls += 1;
|
|
224
|
+
// By tier
|
|
225
|
+
byTier[record.tier].cost += record.costUSD;
|
|
226
|
+
byTier[record.tier].tokens += record.inputTokens + record.outputTokens;
|
|
227
|
+
byTier[record.tier].calls += 1;
|
|
228
|
+
}
|
|
229
|
+
const budgetRemaining = Math.max(0, this.config.budgetUSD - totalCostUSD);
|
|
230
|
+
const budgetUsedPercent = this.config.budgetUSD > 0
|
|
231
|
+
? Math.min(100, (totalCostUSD / this.config.budgetUSD) * 100)
|
|
232
|
+
: 100;
|
|
233
|
+
return {
|
|
234
|
+
totalCostUSD: Math.round(totalCostUSD * 1_000_000) / 1_000_000,
|
|
235
|
+
totalInputTokens,
|
|
236
|
+
totalOutputTokens,
|
|
237
|
+
byModel,
|
|
238
|
+
byTier,
|
|
239
|
+
budgetRemaining: Math.round(budgetRemaining * 1_000_000) / 1_000_000,
|
|
240
|
+
budgetUsedPercent: Math.round(budgetUsedPercent * 100) / 100,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// ── Budget ───────────────────────────────────────────────────────
|
|
244
|
+
/**
|
|
245
|
+
* Check whether the session is still within its budget.
|
|
246
|
+
* Optionally include an additional planned cost to see if it would exceed.
|
|
247
|
+
*/
|
|
248
|
+
isWithinBudget(additionalCostUSD = 0) {
|
|
249
|
+
const spent = this.totalSpent();
|
|
250
|
+
return spent + additionalCostUSD <= this.config.budgetUSD;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Returns a warning string if budget usage has crossed the configured
|
|
254
|
+
* warning threshold. Returns null if usage is below the threshold.
|
|
255
|
+
*/
|
|
256
|
+
getBudgetWarning() {
|
|
257
|
+
const spent = this.totalSpent();
|
|
258
|
+
const usedPercent = this.config.budgetUSD > 0
|
|
259
|
+
? spent / this.config.budgetUSD
|
|
260
|
+
: 1;
|
|
261
|
+
if (usedPercent >= 1.0) {
|
|
262
|
+
return `Budget exhausted: $${spent.toFixed(4)} / $${this.config.budgetUSD.toFixed(2)} (${(usedPercent * 100).toFixed(1)}%)`;
|
|
263
|
+
}
|
|
264
|
+
if (usedPercent >= this.config.costWarningThreshold) {
|
|
265
|
+
return `Budget warning: $${spent.toFixed(4)} / $${this.config.budgetUSD.toFixed(2)} (${(usedPercent * 100).toFixed(1)}% used)`;
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
// ── Lifecycle ────────────────────────────────────────────────────
|
|
270
|
+
/**
|
|
271
|
+
* Reset all recorded usage for a new session.
|
|
272
|
+
* Model registrations and config are preserved.
|
|
273
|
+
*/
|
|
274
|
+
reset() {
|
|
275
|
+
this.records = [];
|
|
276
|
+
}
|
|
277
|
+
// ── Model Management ─────────────────────────────────────────────
|
|
278
|
+
/**
|
|
279
|
+
* Return all registered model profiles.
|
|
280
|
+
*/
|
|
281
|
+
getModels() {
|
|
282
|
+
return Array.from(this.models.values());
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Register a new model or update an existing one.
|
|
286
|
+
*/
|
|
287
|
+
registerModel(profile) {
|
|
288
|
+
this.models.set(profile.name, profile);
|
|
289
|
+
// Keep config.models in sync
|
|
290
|
+
const idx = this.config.models.findIndex((m) => m.name === profile.name);
|
|
291
|
+
if (idx >= 0) {
|
|
292
|
+
this.config.models[idx] = profile;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
this.config.models.push(profile);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// ── Private Helpers ──────────────────────────────────────────────
|
|
299
|
+
/**
|
|
300
|
+
* Resolve the base tier for a task type using the static mapping.
|
|
301
|
+
*/
|
|
302
|
+
resolveBaseTier(taskType) {
|
|
303
|
+
return TASK_TIER_MAP[taskType] ?? this.config.defaultTier;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Shift tier up or down based on complexity label.
|
|
307
|
+
*
|
|
308
|
+
* - "trivial" | "simple" → downgrade one tier (min: cheap)
|
|
309
|
+
* - "complex" | "massive" → upgrade one tier (max: premium)
|
|
310
|
+
* - anything else → no change
|
|
311
|
+
*/
|
|
312
|
+
applyComplexityModifier(tier, complexity) {
|
|
313
|
+
const normalized = complexity.toLowerCase();
|
|
314
|
+
const idx = tierIndex(tier);
|
|
315
|
+
if (normalized === "trivial" || normalized === "simple") {
|
|
316
|
+
return clampTier(idx - 1);
|
|
317
|
+
}
|
|
318
|
+
if (normalized === "complex" || normalized === "massive") {
|
|
319
|
+
return clampTier(idx + 1);
|
|
320
|
+
}
|
|
321
|
+
return tier;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Downgrade tier when budget is under pressure.
|
|
325
|
+
*
|
|
326
|
+
* - If remaining budget < estimated cost × 2 → downgrade one tier
|
|
327
|
+
* - If remaining budget < 10% of total budget → force cheap
|
|
328
|
+
*/
|
|
329
|
+
applyBudgetPressure(tier, taskType, estimatedTokens) {
|
|
330
|
+
const spent = this.totalSpent();
|
|
331
|
+
const remaining = this.config.budgetUSD - spent;
|
|
332
|
+
const budgetFraction = this.config.budgetUSD > 0
|
|
333
|
+
? remaining / this.config.budgetUSD
|
|
334
|
+
: 0;
|
|
335
|
+
// Force cheap when nearly out of budget
|
|
336
|
+
if (budgetFraction < 0.10) {
|
|
337
|
+
return "cheap";
|
|
338
|
+
}
|
|
339
|
+
// Downgrade if the estimated cost is tight
|
|
340
|
+
if (estimatedTokens !== undefined && estimatedTokens > 0) {
|
|
341
|
+
const candidates = this.modelsForTier(tier);
|
|
342
|
+
if (candidates.length > 0) {
|
|
343
|
+
const cheapest = candidates[0]; // sorted cheapest-first
|
|
344
|
+
const ratio = TOKEN_OUTPUT_RATIO[taskType] ?? 1.0;
|
|
345
|
+
const outputEstimate = Math.ceil(estimatedTokens * ratio);
|
|
346
|
+
const estimatedCost = computeCost(cheapest, estimatedTokens, outputEstimate);
|
|
347
|
+
if (remaining < estimatedCost * 2) {
|
|
348
|
+
return clampTier(tierIndex(tier) - 1);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return tier;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Pick the cheapest model in the given tier whose capabilities
|
|
356
|
+
* include the requested task type. Falls back to cheapest in-tier
|
|
357
|
+
* if no capability match, then falls back to the cheapest model overall.
|
|
358
|
+
*/
|
|
359
|
+
pickModelForTier(tier, taskType) {
|
|
360
|
+
const candidates = this.modelsForTier(tier);
|
|
361
|
+
// Prefer models whose capabilities include the task type
|
|
362
|
+
const capable = candidates.filter((m) => m.capabilities.includes(taskType));
|
|
363
|
+
if (capable.length > 0) {
|
|
364
|
+
return capable[0];
|
|
365
|
+
}
|
|
366
|
+
// Fallback: any model in the tier
|
|
367
|
+
if (candidates.length > 0) {
|
|
368
|
+
return candidates[0];
|
|
369
|
+
}
|
|
370
|
+
// Ultimate fallback: cheapest model overall
|
|
371
|
+
const all = this.allModelsSorted();
|
|
372
|
+
if (all.length > 0) {
|
|
373
|
+
return all[0];
|
|
374
|
+
}
|
|
375
|
+
// Should never happen if config has at least one model
|
|
376
|
+
throw new Error(`CostOptimizer: no models registered. Cannot select a model for tier="${tier}" task="${taskType}".`);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Return models for a given tier, sorted by total cost (cheapest first).
|
|
380
|
+
* Total cost heuristic: inputCostPer1M + outputCostPer1M.
|
|
381
|
+
*/
|
|
382
|
+
modelsForTier(tier) {
|
|
383
|
+
return Array.from(this.models.values())
|
|
384
|
+
.filter((m) => m.tier === tier)
|
|
385
|
+
.sort((a, b) => a.inputCostPer1M + a.outputCostPer1M -
|
|
386
|
+
(b.inputCostPer1M + b.outputCostPer1M));
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Return all models sorted by total cost (cheapest first).
|
|
390
|
+
*/
|
|
391
|
+
allModelsSorted() {
|
|
392
|
+
return Array.from(this.models.values()).sort((a, b) => a.inputCostPer1M + a.outputCostPer1M -
|
|
393
|
+
(b.inputCostPer1M + b.outputCostPer1M));
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Sum of all recorded costs so far.
|
|
397
|
+
*/
|
|
398
|
+
totalSpent() {
|
|
399
|
+
let total = 0;
|
|
400
|
+
for (const r of this.records) {
|
|
401
|
+
total += r.costUSD;
|
|
402
|
+
}
|
|
403
|
+
return total;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=cost-optimizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-optimizer.js","sourceRoot":"","sources":["../src/cost-optimizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module execution-policy-engine
|
|
3
|
+
* @description 실행 정책 엔진 — `.yuan/policy.json` 또는 YUAN.md에서 정책을 로드하여
|
|
4
|
+
* 에이전트의 모든 모듈을 단일 소스에서 구성.
|
|
5
|
+
*
|
|
6
|
+
* 로드 순서: DEFAULT_POLICY → .yuan/policy.json → YUAN.md 오버라이드
|
|
7
|
+
*/
|
|
8
|
+
export interface ExecutionPolicy {
|
|
9
|
+
planning: {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
threshold: "simple" | "moderate" | "complex";
|
|
12
|
+
maxDepth: number;
|
|
13
|
+
autoReplan: boolean;
|
|
14
|
+
};
|
|
15
|
+
speculation: {
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
maxApproaches: number;
|
|
18
|
+
minComplexity: "moderate" | "complex" | "massive";
|
|
19
|
+
};
|
|
20
|
+
debate: {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
rounds: number;
|
|
23
|
+
roles: string[];
|
|
24
|
+
minComplexity: "moderate" | "complex" | "massive";
|
|
25
|
+
};
|
|
26
|
+
verification: {
|
|
27
|
+
depth: "shallow" | "standard" | "deep";
|
|
28
|
+
strictness: number;
|
|
29
|
+
autoTest: boolean;
|
|
30
|
+
autoBuild: boolean;
|
|
31
|
+
autoLint: boolean;
|
|
32
|
+
};
|
|
33
|
+
cost: {
|
|
34
|
+
maxTokensPerSession: number;
|
|
35
|
+
maxTokensPerIteration: number;
|
|
36
|
+
budgetPerRole: Record<string, number>;
|
|
37
|
+
preferredModel: string;
|
|
38
|
+
};
|
|
39
|
+
safety: {
|
|
40
|
+
sandboxTier: number;
|
|
41
|
+
approvalLevel: "none" | "dangerous" | "all";
|
|
42
|
+
blockedCommands: string[];
|
|
43
|
+
blockedPaths: string[];
|
|
44
|
+
secretDetection: boolean;
|
|
45
|
+
};
|
|
46
|
+
recovery: {
|
|
47
|
+
maxRetries: number;
|
|
48
|
+
maxStrategySwitches: number;
|
|
49
|
+
enableRollback: boolean;
|
|
50
|
+
enableScopeReduce: boolean;
|
|
51
|
+
escalateThreshold: number;
|
|
52
|
+
};
|
|
53
|
+
memory: {
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
autoSavelearnings: boolean;
|
|
56
|
+
checkpointThreshold: number;
|
|
57
|
+
maxCheckpoints: number;
|
|
58
|
+
};
|
|
59
|
+
mcp: {
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
servers: Array<{
|
|
62
|
+
name: string;
|
|
63
|
+
command: string;
|
|
64
|
+
args?: string[];
|
|
65
|
+
env?: Record<string, string>;
|
|
66
|
+
}>;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export interface PolicySource {
|
|
70
|
+
type: "file" | "yuanmd" | "default";
|
|
71
|
+
path?: string;
|
|
72
|
+
loadedAt: string;
|
|
73
|
+
}
|
|
74
|
+
export declare const DEFAULT_POLICY: ExecutionPolicy;
|
|
75
|
+
export declare class ExecutionPolicyEngine {
|
|
76
|
+
private policy;
|
|
77
|
+
private source;
|
|
78
|
+
private readonly projectPath;
|
|
79
|
+
constructor(projectPath: string);
|
|
80
|
+
/**
|
|
81
|
+
* Load policy: DEFAULT → .yuan/policy.json → YUAN.md overrides.
|
|
82
|
+
*/
|
|
83
|
+
load(): Promise<ExecutionPolicy>;
|
|
84
|
+
/** Get the full current policy. */
|
|
85
|
+
getPolicy(): ExecutionPolicy;
|
|
86
|
+
/** Get a specific policy section. */
|
|
87
|
+
get<K extends keyof ExecutionPolicy>(section: K): ExecutionPolicy[K];
|
|
88
|
+
/** Override a section at runtime (in-memory only, call save() to persist). */
|
|
89
|
+
override<K extends keyof ExecutionPolicy>(section: K, values: Partial<ExecutionPolicy[K]>): void;
|
|
90
|
+
/** Save current policy to .yuan/policy.json (atomic write via tmp + rename). */
|
|
91
|
+
save(): Promise<void>;
|
|
92
|
+
/** Get info about where the policy was loaded from. */
|
|
93
|
+
getSource(): PolicySource;
|
|
94
|
+
/** Merge a partial policy with defaults. */
|
|
95
|
+
static mergeWithDefaults(partial: Partial<ExecutionPolicy>): ExecutionPolicy;
|
|
96
|
+
/** Validate policy values (ranges, enums). Returns all errors, not just the first. */
|
|
97
|
+
static validate(policy: ExecutionPolicy): {
|
|
98
|
+
valid: boolean;
|
|
99
|
+
errors: string[];
|
|
100
|
+
};
|
|
101
|
+
/** Convert policy → GovernorConfig shape. */
|
|
102
|
+
toGovernorConfig(): {
|
|
103
|
+
planTier: string;
|
|
104
|
+
customLimits: Record<string, number>;
|
|
105
|
+
};
|
|
106
|
+
/** Convert policy → AutoFixConfig shape. */
|
|
107
|
+
toAutoFixConfig(): {
|
|
108
|
+
maxRetries: number;
|
|
109
|
+
autoLint: boolean;
|
|
110
|
+
autoTest: boolean;
|
|
111
|
+
autoBuild: boolean;
|
|
112
|
+
};
|
|
113
|
+
/** Convert policy → failure recovery config. */
|
|
114
|
+
toFailureRecoveryConfig(): {
|
|
115
|
+
maxStrategySwitches: number;
|
|
116
|
+
enableRollback: boolean;
|
|
117
|
+
enableScopeReduce: boolean;
|
|
118
|
+
escalateThreshold: number;
|
|
119
|
+
};
|
|
120
|
+
/** Convert policy → ContextManagerConfig shape. */
|
|
121
|
+
toContextManagerConfig(): {
|
|
122
|
+
maxContextTokens: number;
|
|
123
|
+
};
|
|
124
|
+
/** Convert policy → ExecutionEngineConfig shape (general-purpose). */
|
|
125
|
+
toExecutionEngineConfig(): Record<string, unknown>;
|
|
126
|
+
/**
|
|
127
|
+
* Parse YUAN.md for policy overrides.
|
|
128
|
+
* Looks for a `## Policy` or `## Configuration` section, then extracts
|
|
129
|
+
* lines matching `- dotted.key: value`.
|
|
130
|
+
*/
|
|
131
|
+
private parseYuanMd;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=execution-policy-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-policy-engine.d.ts","sourceRoot":"","sources":["../src/execution-policy-engine.ts"],"names":[],"mappings":"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"}
|