@rulvar/core 1.19.0 → 1.20.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/index.d.ts +18 -6
- package/dist/index.js +32 -14
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -602,10 +602,20 @@ type AbandonPayload = {
|
|
|
602
602
|
retainCheckpoint?: boolean; /** Default false; counts against the pin cap (DEF-5). */
|
|
603
603
|
retainWorktree?: boolean;
|
|
604
604
|
};
|
|
605
|
-
/**
|
|
605
|
+
/**
|
|
606
|
+
* One (invocation role, serving model) slice of an agent call's usage.
|
|
607
|
+
* `role` is the phase that PAID the slice (v1.19.0 review P1-2: the
|
|
608
|
+
* loop, extract, finalize, and summarize phases of one agent call must
|
|
609
|
+
* land in their own CostReport.byRole buckets even when a single model
|
|
610
|
+
* serves several of them). Absent on slices written before roles
|
|
611
|
+
* shipped: readers fall back to the entry's primary
|
|
612
|
+
* `costAttribution.role`, exactly like the other documented fallbacks.
|
|
613
|
+
* Policy, never identity.
|
|
614
|
+
*/
|
|
606
615
|
interface UsageSlice {
|
|
607
616
|
servedBy: ModelRef;
|
|
608
617
|
usage: Usage;
|
|
618
|
+
role?: InvocationRole;
|
|
609
619
|
}
|
|
610
620
|
/**
|
|
611
621
|
* Cost-attribution facts a live run knows at settlement and a pure
|
|
@@ -2760,11 +2770,13 @@ interface AgentResult<T> {
|
|
|
2760
2770
|
*/
|
|
2761
2771
|
servedBy: ModelRef;
|
|
2762
2772
|
/**
|
|
2763
|
-
* Present only when the call spanned MORE THAN ONE
|
|
2764
|
-
* loop, extract, finalize, and summarize
|
|
2765
|
-
* usage split per model, so
|
|
2766
|
-
*
|
|
2767
|
-
*
|
|
2773
|
+
* Present only when the call spanned MORE THAN ONE (invocation role,
|
|
2774
|
+
* serving model) pair (the loop, extract, finalize, and summarize
|
|
2775
|
+
* roles resolve independently): usage split per (role, model), so
|
|
2776
|
+
* `costUsd` and every cost bucket price each slice at its own rate
|
|
2777
|
+
* and `CostReport.byRole` attributes each phase to its own bucket
|
|
2778
|
+
* (v1.19.0 review P1-2). Absent for a single-phase single-model call,
|
|
2779
|
+
* which (usage, servedBy) already describes exactly.
|
|
2768
2780
|
*/
|
|
2769
2781
|
usageByModel?: UsageSlice[];
|
|
2770
2782
|
transcriptRef: string;
|
package/dist/index.js
CHANGED
|
@@ -6386,7 +6386,8 @@ function costReportFromJournal(entries, priceUsd) {
|
|
|
6386
6386
|
byPhase[phase] = (byPhase[phase] ?? 0) + priced.usd;
|
|
6387
6387
|
const agentType = facts?.agentType ?? "unknown";
|
|
6388
6388
|
byAgentType[agentType] = (byAgentType[agentType] ?? 0) + priced.usd;
|
|
6389
|
-
|
|
6389
|
+
const primaryRole = facts?.role ?? "loop";
|
|
6390
|
+
for (const slice of priced.priced) byRole[slice.role ?? primaryRole] += slice.usd;
|
|
6390
6391
|
if (facts?.budgetAccount !== void 0 && isOrchestratorAccount(facts.budgetAccount)) {
|
|
6391
6392
|
orchestratorSpentUsd += priced.usd;
|
|
6392
6393
|
if (facts.finalizeReserve === true) reserveUsedUsd += priced.usd;
|
|
@@ -8058,7 +8059,17 @@ async function runAgent(options) {
|
|
|
8058
8059
|
}]
|
|
8059
8060
|
}];
|
|
8060
8061
|
let totalUsage = ZERO_USAGE$1;
|
|
8061
|
-
const
|
|
8062
|
+
const primaryRole = options.role ?? "loop";
|
|
8063
|
+
const usageByPhaseModel = /* @__PURE__ */ new Map();
|
|
8064
|
+
const addPhaseUsage = (role, ref, usage) => {
|
|
8065
|
+
const key = `${role}${ref}`;
|
|
8066
|
+
const prior = usageByPhaseModel.get(key);
|
|
8067
|
+
usageByPhaseModel.set(key, {
|
|
8068
|
+
role,
|
|
8069
|
+
servedBy: ref,
|
|
8070
|
+
usage: addUsage(prior?.usage ?? ZERO_USAGE$1, usage)
|
|
8071
|
+
});
|
|
8072
|
+
};
|
|
8062
8073
|
let turns = 0;
|
|
8063
8074
|
let schemaAttempts = 0;
|
|
8064
8075
|
let output = null;
|
|
@@ -8093,13 +8104,14 @@ async function runAgent(options) {
|
|
|
8093
8104
|
usage: restored.usage
|
|
8094
8105
|
}];
|
|
8095
8106
|
for (const slice of restoredSlices) {
|
|
8096
|
-
|
|
8107
|
+
addPhaseUsage(slice.role ?? primaryRole, slice.servedBy, slice.usage);
|
|
8097
8108
|
options.budget?.onUsage(slice.usage, slice.servedBy);
|
|
8098
8109
|
}
|
|
8099
8110
|
}
|
|
8100
|
-
const usageSlices = () => [...
|
|
8111
|
+
const usageSlices = () => [...usageByPhaseModel.values()].map(({ role, servedBy: sliceServedBy, usage }) => ({
|
|
8101
8112
|
servedBy: sliceServedBy,
|
|
8102
|
-
usage
|
|
8113
|
+
usage,
|
|
8114
|
+
role
|
|
8103
8115
|
}));
|
|
8104
8116
|
/**
|
|
8105
8117
|
* Every slice priced at ITS OWN model's rate. An unpriced model
|
|
@@ -8110,7 +8122,7 @@ async function runAgent(options) {
|
|
|
8110
8122
|
const price = options.priceUsd;
|
|
8111
8123
|
if (price === void 0) return 0;
|
|
8112
8124
|
let usd = 0;
|
|
8113
|
-
for (const
|
|
8125
|
+
for (const slice of usageByPhaseModel.values()) usd += price(slice.servedBy, slice.usage) ?? 0;
|
|
8114
8126
|
return usd;
|
|
8115
8127
|
};
|
|
8116
8128
|
const saveBoundary = async (pending) => {
|
|
@@ -8343,17 +8355,17 @@ async function runAgent(options) {
|
|
|
8343
8355
|
agentType,
|
|
8344
8356
|
label: options.label,
|
|
8345
8357
|
model: servedBy,
|
|
8346
|
-
role:
|
|
8358
|
+
role: primaryRole
|
|
8347
8359
|
});
|
|
8348
8360
|
let invariantViolation;
|
|
8349
|
-
const recordUsage = (usage, reported, adapterId, ref) => {
|
|
8361
|
+
const recordUsage = (usage, reported, adapterId, ref, role) => {
|
|
8350
8362
|
try {
|
|
8351
8363
|
assertUsageInvariant(usage, adapterId);
|
|
8352
8364
|
} catch (thrown) {
|
|
8353
8365
|
invariantViolation = thrown instanceof Error ? thrown.message : String(thrown);
|
|
8354
8366
|
}
|
|
8355
8367
|
totalUsage = addUsage(totalUsage, usage);
|
|
8356
|
-
|
|
8368
|
+
addPhaseUsage(role, ref, usage);
|
|
8357
8369
|
const remainder = {
|
|
8358
8370
|
inputTokens: Math.max(0, usage.inputTokens - reported.inputTokens),
|
|
8359
8371
|
outputTokens: Math.max(0, usage.outputTokens - reported.outputTokens),
|
|
@@ -8375,7 +8387,7 @@ async function runAgent(options) {
|
|
|
8375
8387
|
inner: for (;;) {
|
|
8376
8388
|
const dispatch = () => streamTurn(target.adapter, site.requestFor(target), site.streamOptionsFor(target));
|
|
8377
8389
|
const outcome = await (options.providerSlot === void 0 ? dispatch() : options.providerSlot(target.adapter.id, dispatch));
|
|
8378
|
-
recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref);
|
|
8390
|
+
recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref, site.role);
|
|
8379
8391
|
tries += 1;
|
|
8380
8392
|
const retryClass = outcome.aborted === "idle" ? "transport" : outcome.wireError === void 0 ? void 0 : retryClassOf(outcome.wireError);
|
|
8381
8393
|
if (retryClass === void 0) return {
|
|
@@ -8452,6 +8464,7 @@ async function runAgent(options) {
|
|
|
8452
8464
|
let loopDispatch;
|
|
8453
8465
|
try {
|
|
8454
8466
|
loopDispatch = await dispatchPhase({
|
|
8467
|
+
role: primaryRole,
|
|
8455
8468
|
chain: loopChain,
|
|
8456
8469
|
cursor: loopCursor,
|
|
8457
8470
|
requestFor: (target) => {
|
|
@@ -8643,6 +8656,7 @@ async function runAgent(options) {
|
|
|
8643
8656
|
let summaryDispatch;
|
|
8644
8657
|
try {
|
|
8645
8658
|
summaryDispatch = await dispatchPhase({
|
|
8659
|
+
role: "summarize",
|
|
8646
8660
|
chain: [{
|
|
8647
8661
|
adapter: options.summarize.adapter,
|
|
8648
8662
|
resolved: options.summarize.resolved
|
|
@@ -8822,6 +8836,7 @@ async function runAgent(options) {
|
|
|
8822
8836
|
let finalizeDispatch;
|
|
8823
8837
|
try {
|
|
8824
8838
|
finalizeDispatch = await dispatchPhase({
|
|
8839
|
+
role: "finalize",
|
|
8825
8840
|
chain: [{
|
|
8826
8841
|
adapter: options.finalize.adapter,
|
|
8827
8842
|
resolved: options.finalize.resolved
|
|
@@ -8944,6 +8959,7 @@ async function runAgent(options) {
|
|
|
8944
8959
|
let extractDispatch;
|
|
8945
8960
|
try {
|
|
8946
8961
|
extractDispatch = await dispatchPhase({
|
|
8962
|
+
role: "extract",
|
|
8947
8963
|
chain: extractChain,
|
|
8948
8964
|
cursor: extractCursor,
|
|
8949
8965
|
requestFor: (target) => {
|
|
@@ -9047,7 +9063,7 @@ async function runAgent(options) {
|
|
|
9047
9063
|
servedBy,
|
|
9048
9064
|
transcriptRef
|
|
9049
9065
|
};
|
|
9050
|
-
if (
|
|
9066
|
+
if (usageByPhaseModel.size > 1) result.usageByModel = usageSlices();
|
|
9051
9067
|
if (agentError !== void 0) result.error = agentError;
|
|
9052
9068
|
if (escalationRequest !== void 0) result.escalationRequest = escalationRequest;
|
|
9053
9069
|
if (abortClass !== void 0) result.abortClass = abortClass;
|
|
@@ -11062,10 +11078,11 @@ function createCtx(internals, rootWorkflow) {
|
|
|
11062
11078
|
});
|
|
11063
11079
|
}
|
|
11064
11080
|
const usd = result.costUsd;
|
|
11065
|
-
|
|
11081
|
+
const attributionSlices = result.usageByModel ?? [{
|
|
11066
11082
|
servedBy: result.servedBy,
|
|
11067
11083
|
usage: result.usage
|
|
11068
|
-
}]
|
|
11084
|
+
}];
|
|
11085
|
+
for (const slice of attributionSlices) {
|
|
11069
11086
|
const priced = internals.priceUsd(slice.servedBy, slice.usage);
|
|
11070
11087
|
if (priced === void 0) {
|
|
11071
11088
|
internals.cost.unpriced.push({
|
|
@@ -11075,10 +11092,11 @@ function createCtx(internals, rootWorkflow) {
|
|
|
11075
11092
|
continue;
|
|
11076
11093
|
}
|
|
11077
11094
|
bump(internals.cost.byModel, slice.servedBy, priced);
|
|
11095
|
+
const sliceRole = slice.role ?? primaryRole;
|
|
11096
|
+
internals.cost.byRole.set(sliceRole, (internals.cost.byRole.get(sliceRole) ?? 0) + priced);
|
|
11078
11097
|
}
|
|
11079
11098
|
bump(internals.cost.byPhase, state.phase ?? "", usd);
|
|
11080
11099
|
bump(internals.cost.byAgentType, agentType, usd);
|
|
11081
|
-
internals.cost.byRole.set(primaryRole, (internals.cost.byRole.get(primaryRole) ?? 0) + usd);
|
|
11082
11100
|
if (result.error?.kind === "budget" || internals.budget.exhausted && result.status !== "ok") {
|
|
11083
11101
|
const diagnostics = internals.budget.exhaustionDiagnostics(state.budgetScope ?? "run");
|
|
11084
11102
|
const crossed = diagnostics.crossed;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "Rulvar core: L0 contracts, journal kernel, ctx primitives, agent runtime, model router, tool system, dynamic orchestrator, InMemory and JSONL stores, event stream.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|