@rulvar/cli 1.6.0 → 1.8.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/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CURRENT_HASH_VERSION, ConfigError, DedupIndex, InMemoryStore, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LineageIndex, PlanInvariantError, ROOT_ACCOUNT, ReplayPlanHashMismatch, TerminationAccount, approachSigCoarse, buildTerminationInitValue, canonicalIsolationTag, canonicalizeLadder, checkpointRefFor, countsAgainstLimit, createEngine, defineWorkflow, deriverV2, evaluateReuse, foldTermination, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, makeOrchestratorWorkflow, nodeLinkKey, normalizeApproachTag, orchestrate, planNodeScope, profileRegistrySnapshotHash, tool, validateTerminationLimits } from "@rulvar/core";
|
|
1
|
+
import { AdmissionRejectedError, BudgetExhaustedError, CURRENT_HASH_VERSION, ConfigError, DedupIndex, InMemoryStore, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LineageIndex, PlanInvariantError, ROOT_ACCOUNT, ReplayPlanHashMismatch, TerminationAccount, approachSigCoarse, buildTerminationInitValue, canonicalIsolationTag, canonicalizeLadder, checkpointRefFor, countsAgainstLimit, createEngine, defineWorkflow, deriverV2, evaluateReuse, foldTermination, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, makeOrchestratorWorkflow, nodeLinkKey, normalizeApproachTag, orchestrate, planNodeScope, profileRegistrySnapshotHash, tool, validateTerminationLimits } from "@rulvar/core";
|
|
2
2
|
//#region ../plan/dist/index.js
|
|
3
3
|
/**
|
|
4
4
|
* Plan scope substrate (M7-T01): TaskPlan as engine-owned typed data, the
|
|
@@ -3053,17 +3053,51 @@ function planRunner(options) {
|
|
|
3053
3053
|
...ladder === void 0 ? {} : ladderDispatchFields(node, spec, ladder)
|
|
3054
3054
|
};
|
|
3055
3055
|
};
|
|
3056
|
+
/**
|
|
3057
|
+
* A dispatch refused by budget/admission facts that changed AFTER the
|
|
3058
|
+
* op was admitted (another child consumed the shared parent between
|
|
3059
|
+
* turns, a rung ceiling re-resolved differently) lands as a terminal
|
|
3060
|
+
* plan decision: the node fails loudly instead of sitting ready
|
|
3061
|
+
* forever, the other ready nodes still dispatch, and the wake digest
|
|
3062
|
+
* carries the failure to the orchestrator (the v1.7.0 follow-up
|
|
3063
|
+
* review's P1: no stranded node without a dispatch root or terminal
|
|
3064
|
+
* decision). Everything else (engine bugs) still propagates.
|
|
3065
|
+
*/
|
|
3066
|
+
const landDispatchRejection = async (node, from, thrown) => {
|
|
3067
|
+
const message = thrown instanceof Error ? thrown.message : String(thrown);
|
|
3068
|
+
io.emit({
|
|
3069
|
+
type: "log",
|
|
3070
|
+
level: "warn",
|
|
3071
|
+
msg: `plan node ${node.nodeId} failed dispatch admission and lands terminally failed: ${message}`,
|
|
3072
|
+
data: {
|
|
3073
|
+
nodeId: node.nodeId,
|
|
3074
|
+
logicalTaskId: node.logicalTaskId
|
|
3075
|
+
}
|
|
3076
|
+
});
|
|
3077
|
+
await appendPlanDecision("dispatch-rejected", [{
|
|
3078
|
+
kind: "set_node_status",
|
|
3079
|
+
nodeId: node.nodeId,
|
|
3080
|
+
from,
|
|
3081
|
+
to: "failed",
|
|
3082
|
+
cause: "dispatch-rejected",
|
|
3083
|
+
causeRef: Math.max(planCursor, 0)
|
|
3084
|
+
}], Math.max(planCursor, 0));
|
|
3085
|
+
};
|
|
3086
|
+
const isDispatchRejection = (thrown) => thrown instanceof AdmissionRejectedError || thrown instanceof BudgetExhaustedError;
|
|
3056
3087
|
/** Dispatches every ready node under its plan/NodeId scope. */
|
|
3057
3088
|
const scheduleReady = async () => {
|
|
3058
3089
|
for (const node of Object.values(fold.plan.nodes)) {
|
|
3059
3090
|
if (node.status === "running" && !dispatched.has(node.nodeId)) {
|
|
3060
3091
|
const spec = fold.specs[node.nodeId];
|
|
3061
|
-
if (spec !== void 0) {
|
|
3092
|
+
if (spec !== void 0) try {
|
|
3062
3093
|
const { handle } = await io.dispatch(buildDispatchSpec(node, spec), nodeScopeOf(node.nodeId), {
|
|
3063
3094
|
nodeId: node.nodeId,
|
|
3064
3095
|
logicalTaskId: node.logicalTaskId
|
|
3065
3096
|
});
|
|
3066
3097
|
dispatched.set(node.nodeId, handle);
|
|
3098
|
+
} catch (thrown) {
|
|
3099
|
+
if (!isDispatchRejection(thrown)) throw thrown;
|
|
3100
|
+
await landDispatchRejection(node, "running", thrown);
|
|
3067
3101
|
}
|
|
3068
3102
|
continue;
|
|
3069
3103
|
}
|
|
@@ -3090,10 +3124,17 @@ function planRunner(options) {
|
|
|
3090
3124
|
}
|
|
3091
3125
|
const spec = fold.specs[node.nodeId];
|
|
3092
3126
|
if (spec === void 0) continue;
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3127
|
+
let handle;
|
|
3128
|
+
try {
|
|
3129
|
+
({handle} = await io.dispatch(buildDispatchSpec(node, spec), nodeScopeOf(node.nodeId), {
|
|
3130
|
+
nodeId: node.nodeId,
|
|
3131
|
+
logicalTaskId: node.logicalTaskId
|
|
3132
|
+
}));
|
|
3133
|
+
} catch (thrown) {
|
|
3134
|
+
if (!isDispatchRejection(thrown)) throw thrown;
|
|
3135
|
+
await landDispatchRejection(node, "ready", thrown);
|
|
3136
|
+
continue;
|
|
3137
|
+
}
|
|
3097
3138
|
dispatched.set(node.nodeId, handle);
|
|
3098
3139
|
await appendPlanDecision("child-result", [{
|
|
3099
3140
|
kind: "set_node_status",
|
|
@@ -3174,6 +3215,14 @@ function planRunner(options) {
|
|
|
3174
3215
|
return { entryRef: entry.seq };
|
|
3175
3216
|
},
|
|
3176
3217
|
planRevise: async (request) => writeLock.runExclusive(async () => {
|
|
3218
|
+
const withVerdictDetail = (outcomes, admissions) => outcomes.map((outcome, opIndex) => {
|
|
3219
|
+
if (outcome.kind !== "dropped" || outcome.reason !== "admission_denied") return outcome;
|
|
3220
|
+
const verdict = admissions.find((admission) => admission.opIndex === opIndex)?.decision.verdict;
|
|
3221
|
+
return verdict !== void 0 && verdict.kind === "reject" ? {
|
|
3222
|
+
...outcome,
|
|
3223
|
+
verdictReason: verdict.reason
|
|
3224
|
+
} : outcome;
|
|
3225
|
+
});
|
|
3177
3226
|
await io.flush();
|
|
3178
3227
|
absorbPlan();
|
|
3179
3228
|
absorbGuardVerdicts();
|
|
@@ -3203,7 +3252,7 @@ function planRunner(options) {
|
|
|
3203
3252
|
}
|
|
3204
3253
|
await scheduleReady();
|
|
3205
3254
|
return {
|
|
3206
|
-
outcomes: value.outcomes,
|
|
3255
|
+
outcomes: withVerdictDetail(value.outcomes, value.admissions),
|
|
3207
3256
|
assignedNodeIds: value.assignedNodeIds,
|
|
3208
3257
|
planHashAfter: value.planHashAfter,
|
|
3209
3258
|
droppedAll: value.outcomes.every((outcome) => outcome.kind === "dropped"),
|
|
@@ -3217,6 +3266,7 @@ function planRunner(options) {
|
|
|
3217
3266
|
const freshNotes = /* @__PURE__ */ new Map();
|
|
3218
3267
|
const frozen = io.snapshot().some((candidate) => candidate.kind === "decision" && candidate.value?.decisionType === "orchestrator_budget_cap");
|
|
3219
3268
|
const claimedThisRevision = /* @__PURE__ */ new Set();
|
|
3269
|
+
let pendingReserveUsd = 0;
|
|
3220
3270
|
const evaluation = rebasePlanRevision(request, {
|
|
3221
3271
|
state: fold,
|
|
3222
3272
|
frozen,
|
|
@@ -3283,13 +3333,47 @@ function planRunner(options) {
|
|
|
3283
3333
|
depth: 1
|
|
3284
3334
|
}
|
|
3285
3335
|
};
|
|
3336
|
+
const profile = io.profiles[op.spec.agentType];
|
|
3337
|
+
const childAccount = rootScope === "" ? planNodeScope(nodeId) : `${rootScope}/${planNodeScope(nodeId)}`;
|
|
3338
|
+
const ladder = canonicalLadderOf(profile);
|
|
3339
|
+
const dispatchCeilingUsd = (() => {
|
|
3340
|
+
if (ladder !== void 0) {
|
|
3341
|
+
const startTier = clampStartTier(ladder, op.spec.model_hint?.startTier);
|
|
3342
|
+
const raises = op.lineage === void 0 ? 0 : requireAccount().rungIndexOf(op.lineage.continues);
|
|
3343
|
+
const rung = ladder.rungs[executingRungOf(ladder, startTier, raises)];
|
|
3344
|
+
if (rung?.maxCostUsd !== void 0) return rung.maxCostUsd;
|
|
3345
|
+
}
|
|
3346
|
+
return op.spec.budgetUsd;
|
|
3347
|
+
})();
|
|
3348
|
+
if (profile?.estCost !== void 0 && dispatchCeilingUsd !== void 0 && profile.estCost > dispatchCeilingUsd) return {
|
|
3349
|
+
verdict: {
|
|
3350
|
+
kind: "reject",
|
|
3351
|
+
reason: {
|
|
3352
|
+
code: "reserve_exceeds_budget",
|
|
3353
|
+
agentType: op.spec.agentType,
|
|
3354
|
+
childAccount,
|
|
3355
|
+
estCostUsd: profile.estCost,
|
|
3356
|
+
resolvedReserveUsd: Math.min(profile.estCost, dispatchCeilingUsd),
|
|
3357
|
+
childCeilingUsd: dispatchCeilingUsd,
|
|
3358
|
+
minimumBudgetUsd: profile.estCost,
|
|
3359
|
+
message: `agent profile '${op.spec.agentType}' declares estCost ${profile.estCost.toFixed(4)} USD, which cannot fit the child ceiling ${dispatchCeilingUsd.toFixed(4)} USD of account '${childAccount}'; raise budgetUsd to at least ${profile.estCost.toFixed(4)} or pick a cheaper profile`
|
|
3360
|
+
}
|
|
3361
|
+
},
|
|
3362
|
+
statsBefore: {
|
|
3363
|
+
spawnsBefore: 0,
|
|
3364
|
+
childrenOfParentBefore: 0,
|
|
3365
|
+
depth: 1
|
|
3366
|
+
}
|
|
3367
|
+
};
|
|
3286
3368
|
const admitted = io.admission.admit({
|
|
3287
3369
|
origin: "spawn_agent",
|
|
3288
3370
|
name: op.spec.agentType,
|
|
3289
|
-
childScope:
|
|
3371
|
+
childScope: childAccount,
|
|
3290
3372
|
parentAccountScope: ROOT_ACCOUNT,
|
|
3291
3373
|
nodeKey: planScope,
|
|
3292
3374
|
...op.spec.budgetUsd === void 0 ? {} : { budgetUsd: op.spec.budgetUsd },
|
|
3375
|
+
...profile?.estCost === void 0 ? {} : { estCostUsd: profile.estCost },
|
|
3376
|
+
...pendingReserveUsd === 0 ? {} : { pendingReserveUsd },
|
|
3293
3377
|
...op.lineage === void 0 ? {} : { lineage: op.lineage },
|
|
3294
3378
|
...(op.approach ?? op.spec.approach) === void 0 ? {} : { approach: op.approach ?? op.spec.approach },
|
|
3295
3379
|
signature: {
|
|
@@ -3298,6 +3382,10 @@ function planRunner(options) {
|
|
|
3298
3382
|
},
|
|
3299
3383
|
ladderLength: ladderLengthOf(io.profiles[op.spec.agentType])
|
|
3300
3384
|
}, { commitReserve: false });
|
|
3385
|
+
if (admitted.verdict.kind === "admit") pendingReserveUsd += io.admission.projectedDispatchReserveUsd({
|
|
3386
|
+
...profile?.estCost === void 0 ? {} : { estCostUsd: profile.estCost },
|
|
3387
|
+
...op.spec.budgetUsd === void 0 ? {} : { budgetUsd: op.spec.budgetUsd }
|
|
3388
|
+
});
|
|
3301
3389
|
const note = freshNotes.get(opIndex);
|
|
3302
3390
|
if (note !== void 0 && admitted.verdict.kind === "admit") return {
|
|
3303
3391
|
...admitted,
|
|
@@ -3311,12 +3399,13 @@ function planRunner(options) {
|
|
|
3311
3399
|
admitUnpark: (op, node) => {
|
|
3312
3400
|
const spec = fold.specs[op.nodeId];
|
|
3313
3401
|
const wasDispatched = nodeRootOf(op.nodeId) !== void 0;
|
|
3314
|
-
|
|
3402
|
+
const unparkAdmitted = io.admission.admit({
|
|
3315
3403
|
origin: "spawn_agent",
|
|
3316
3404
|
name: spec?.agentType ?? "unknown",
|
|
3317
3405
|
childScope: nodeScopeOf(op.nodeId),
|
|
3318
3406
|
parentAccountScope: ROOT_ACCOUNT,
|
|
3319
3407
|
nodeKey: planScope,
|
|
3408
|
+
...pendingReserveUsd === 0 ? {} : { pendingReserveUsd },
|
|
3320
3409
|
...wasDispatched ? { lineage: {
|
|
3321
3410
|
continues: node.logicalTaskId,
|
|
3322
3411
|
causeRef: node.checkpointRef ?? Math.max(planCursor, 1),
|
|
@@ -3328,6 +3417,8 @@ function planRunner(options) {
|
|
|
3328
3417
|
},
|
|
3329
3418
|
ladderLength: ladderLengthOf(io.profiles[spec?.agentType ?? ""])
|
|
3330
3419
|
}, { commitReserve: false });
|
|
3420
|
+
if (unparkAdmitted.verdict.kind === "admit") pendingReserveUsd += io.admission.projectedDispatchReserveUsd({});
|
|
3421
|
+
return unparkAdmitted;
|
|
3331
3422
|
},
|
|
3332
3423
|
lineageCheck: (continues) => {
|
|
3333
3424
|
const index = io.admission.lineage();
|
|
@@ -3362,19 +3453,6 @@ function planRunner(options) {
|
|
|
3362
3453
|
consumedRevisionSeqs.add(entry.seq);
|
|
3363
3454
|
await io.flush();
|
|
3364
3455
|
absorbPlan();
|
|
3365
|
-
await drainGuardVerdicts();
|
|
3366
|
-
await landReuseLinks(entry);
|
|
3367
|
-
await landCancelAbandons(value, entry.seq);
|
|
3368
|
-
await landRevisionEscalations(value);
|
|
3369
|
-
for (const outcome of evaluation.outcomes) {
|
|
3370
|
-
if (outcome.kind === "dropped") continue;
|
|
3371
|
-
const applied = outcome.kind === "applied" ? outcome.op : outcome.applied;
|
|
3372
|
-
if ((applied.op === "cancel_task" || applied.op === "park_task") && applied.requestOnly === true) {
|
|
3373
|
-
const handle = dispatched.get(applied.nodeId);
|
|
3374
|
-
if (handle !== void 0) io.cancel(handle, applied.op === "cancel_task" ? applied.reason : "park_task");
|
|
3375
|
-
}
|
|
3376
|
-
}
|
|
3377
|
-
await scheduleReady();
|
|
3378
3456
|
const appliedCount = evaluation.outcomes.filter((o) => o.kind !== "dropped").length;
|
|
3379
3457
|
io.emit({
|
|
3380
3458
|
type: "plan:revised",
|
|
@@ -3391,8 +3469,21 @@ function planRunner(options) {
|
|
|
3391
3469
|
remaining: debit.balanceAfter,
|
|
3392
3470
|
phi: requireAccount().phi()
|
|
3393
3471
|
});
|
|
3472
|
+
await drainGuardVerdicts();
|
|
3473
|
+
await landReuseLinks(entry);
|
|
3474
|
+
await landCancelAbandons(value, entry.seq);
|
|
3475
|
+
await landRevisionEscalations(value);
|
|
3476
|
+
for (const outcome of evaluation.outcomes) {
|
|
3477
|
+
if (outcome.kind === "dropped") continue;
|
|
3478
|
+
const applied = outcome.kind === "applied" ? outcome.op : outcome.applied;
|
|
3479
|
+
if ((applied.op === "cancel_task" || applied.op === "park_task") && applied.requestOnly === true) {
|
|
3480
|
+
const handle = dispatched.get(applied.nodeId);
|
|
3481
|
+
if (handle !== void 0) io.cancel(handle, applied.op === "cancel_task" ? applied.reason : "park_task");
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
await scheduleReady();
|
|
3394
3485
|
return {
|
|
3395
|
-
outcomes: evaluation.outcomes,
|
|
3486
|
+
outcomes: withVerdictDetail(evaluation.outcomes, evaluation.admissions),
|
|
3396
3487
|
assignedNodeIds: evaluation.assignedNodeIds,
|
|
3397
3488
|
planHashAfter: evaluation.planHashAfter,
|
|
3398
3489
|
droppedAll: evaluation.droppedAll,
|
|
@@ -3486,8 +3577,8 @@ function planRunner(options) {
|
|
|
3486
3577
|
maxDepth: options?.limits?.maxDepth ?? 1,
|
|
3487
3578
|
kMax: kMaxOf(io.profiles),
|
|
3488
3579
|
runBudgetUsdCeiling: io.runCeilingUsd ?? 0,
|
|
3489
|
-
orchestratorCapUsd: 0,
|
|
3490
|
-
finalizeReserveUsd: 0
|
|
3580
|
+
orchestratorCapUsd: io.orchestratorCapUsd ?? 0,
|
|
3581
|
+
finalizeReserveUsd: io.finalizeReserveUsd ?? 0
|
|
3491
3582
|
});
|
|
3492
3583
|
const value = buildTerminationInitValue(limits, profileRegistrySnapshotHash(io.profiles));
|
|
3493
3584
|
await io.append({
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resumeCommand, c as driveRun, d as renderEventLine, f as DEFAULT_STORE_DIR, g as looksLikeFile, h as loadWorkflowModule, i as inspectCommand, l as reportOutcome, m as loadCliConfig, n as HELP, o as runCommand, p as assembleEngine, r as runCli, s as runsLsCommand, t as processIo, u as attachProgress } from "./io-
|
|
1
|
+
import { a as resumeCommand, c as driveRun, d as renderEventLine, f as DEFAULT_STORE_DIR, g as looksLikeFile, h as loadWorkflowModule, i as inspectCommand, l as reportOutcome, m as loadCliConfig, n as HELP, o as runCommand, p as assembleEngine, r as runCli, s as runsLsCommand, t as processIo, u as attachProgress } from "./io-CmDfbnun.js";
|
|
2
2
|
import { ConfigError, InvalidResolutionError, JournalCompatibilityError, LeaseHeldError, Replayer, RulvarError, buildDeriverRegistry, costReportFromJournal, maskSecrets, normalizeEntry, scanJournalCompatibility, validateSchemaSpec } from "@rulvar/core";
|
|
3
3
|
//#region src/server.ts
|
|
4
4
|
/**
|
|
@@ -557,7 +557,7 @@ async function kbInboxCommand(argv, context) {
|
|
|
557
557
|
if (flags.positionals.length > 0) throw new ConfigError("usage: rulvar kb inbox [--store PATH]");
|
|
558
558
|
let plan;
|
|
559
559
|
try {
|
|
560
|
-
plan = await import("./dist-
|
|
560
|
+
plan = await import("./dist-A5zLp_kr.js");
|
|
561
561
|
} catch {
|
|
562
562
|
throw new ConfigError("rulvar kb inbox requires @rulvar/plan (the RunLedger fold behind the LedgerExport seam)");
|
|
563
563
|
}
|
|
@@ -700,7 +700,7 @@ async function kbGateCommand(argv, context) {
|
|
|
700
700
|
].includes(confidence)) throw new ConfigError(`--confidence must be high, medium or low, got '${String(values.confidence)}'`);
|
|
701
701
|
let plan;
|
|
702
702
|
try {
|
|
703
|
-
plan = await import("./dist-
|
|
703
|
+
plan = await import("./dist-A5zLp_kr.js");
|
|
704
704
|
} catch {
|
|
705
705
|
throw new ConfigError("rulvar kb gate requires @rulvar/plan (the RunLedger fold behind the LedgerExport seam)");
|
|
706
706
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Rulvar shell: run/resume/runs/inspect/plan/kb commands, TUI progress, createServer, createWorker, OTel exporter.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -22,17 +22,17 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@rulvar/core": "1.
|
|
25
|
+
"@rulvar/core": "1.8.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.20.0",
|
|
29
29
|
"tsdown": "^0.22.3",
|
|
30
30
|
"typescript": "~6.0.3",
|
|
31
|
-
"@rulvar/testing": "1.
|
|
32
|
-
"@rulvar/store-sqlite": "1.
|
|
33
|
-
"@rulvar/planner": "1.
|
|
34
|
-
"@rulvar/plan": "1.
|
|
35
|
-
"@rulvar/evals": "1.
|
|
31
|
+
"@rulvar/testing": "1.8.0",
|
|
32
|
+
"@rulvar/store-sqlite": "1.8.0",
|
|
33
|
+
"@rulvar/planner": "1.8.0",
|
|
34
|
+
"@rulvar/plan": "1.8.0",
|
|
35
|
+
"@rulvar/evals": "1.8.0"
|
|
36
36
|
},
|
|
37
37
|
"bin": {
|
|
38
38
|
"rulvar": "./dist/cli.js"
|