@rulvar/core 1.75.1 → 1.76.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 +57 -0
- package/dist/index.js +83 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7126,6 +7126,30 @@ interface FinishValidationSpec {
|
|
|
7126
7126
|
*/
|
|
7127
7127
|
repairTurnReserve?: number;
|
|
7128
7128
|
/**
|
|
7129
|
+
* The coordination draft gate (the v1.74 experiment review, P0.3),
|
|
7130
|
+
* meaningful ONLY with `synthesis` configured: with validators bound
|
|
7131
|
+
* to the synthesis finish, the coordination finish is an unvalidated
|
|
7132
|
+
* draft, and the experiment's model escaped six failed finish
|
|
7133
|
+
* exchanges with the schema-valid draft 'test', which then starved
|
|
7134
|
+
* synthesis of every citation the validators demanded. The policy
|
|
7135
|
+
* runs deterministic library checks on each coordination finish
|
|
7136
|
+
* (whitespace-token `minWords`, literal `requireSections` markers,
|
|
7137
|
+
* the wordCountValidator and requiredSectionsValidator semantics);
|
|
7138
|
+
* a failing draft returns to the model as the finish call's error
|
|
7139
|
+
* result and the turn continues, exactly like a host validation
|
|
7140
|
+
* rejection, and `repairTurnReserve` grants coordination the same
|
|
7141
|
+
* per-rejected-exchange headroom it grants the synthesis finish.
|
|
7142
|
+
* Pure text checks over the durable exchange: nothing journals, a
|
|
7143
|
+
* resumed segment recounts identically, and `maxRepairs` is not
|
|
7144
|
+
* consumed (it belongs to the synthesis-bound validators). Absent =
|
|
7145
|
+
* byte identical pre 1.76 behavior; configured without `synthesis` =
|
|
7146
|
+
* ConfigError.
|
|
7147
|
+
*/
|
|
7148
|
+
draftPolicy?: {
|
|
7149
|
+
/** Minimum whitespace-separated words the draft must carry. */minWords?: number; /** Literal markers the draft text must contain. */
|
|
7150
|
+
requireSections?: string[];
|
|
7151
|
+
};
|
|
7152
|
+
/**
|
|
7129
7153
|
* The unified output contract this validator set enforces (the v1.71
|
|
7130
7154
|
* experiment review, P0.1/P0.2). Construction then runs the golden
|
|
7131
7155
|
* self test with the contract's fixtures as defaults, the contract's
|
|
@@ -7286,6 +7310,31 @@ interface OrchestrateSynthesis {
|
|
|
7286
7310
|
* { maxTurns: 2 }. Ignored in 'single' mode.
|
|
7287
7311
|
*/
|
|
7288
7312
|
noteLimits?: UsageLimits;
|
|
7313
|
+
/**
|
|
7314
|
+
* Give the 'single' synthesis invocation the RV-201 evidence tools
|
|
7315
|
+
* `get_child_result` and `read_child_artifact` beside `finish` (the
|
|
7316
|
+
* v1.74 experiment review, P0.2): the finish validators hold the
|
|
7317
|
+
* result against the FULL child outputs while the synthesis model
|
|
7318
|
+
* sees 400 char digests, so when the coordination draft collapses the
|
|
7319
|
+
* evidence the validators demand is model-invisible. With the tools
|
|
7320
|
+
* exposed the digest rows in the synthesis prompt carry each child's
|
|
7321
|
+
* `handle`, and the model pages any settled child's full output or
|
|
7322
|
+
* artifacts before finishing. Off by default: the synthesis toolset
|
|
7323
|
+
* and prompt stay byte identical, exactly like the coordination
|
|
7324
|
+
* `exposeChildResultTools`.
|
|
7325
|
+
*/
|
|
7326
|
+
exposeChildResultTools?: boolean;
|
|
7327
|
+
/**
|
|
7328
|
+
* What the 'single' synthesis prompt embeds beside the draft (the
|
|
7329
|
+
* v1.74 experiment review, P0.2). Default 'digests': the 400 char
|
|
7330
|
+
* settled digest rows, byte identical to pre 1.76. 'full' appends a
|
|
7331
|
+
* CHILD OUTPUTS section carrying every settled child's FULL
|
|
7332
|
+
* serialized output after the digest rows: the whole evidence pool
|
|
7333
|
+
* the validators judge against rides the prompt, paid as input
|
|
7334
|
+
* tokens (declare `estCost` or the preflight `estInputTokens`
|
|
7335
|
+
* accordingly).
|
|
7336
|
+
*/
|
|
7337
|
+
context?: "digests" | "full";
|
|
7289
7338
|
}
|
|
7290
7339
|
/**
|
|
7291
7340
|
* The deterministic reconciliation envelope an 'incremental' synthesis
|
|
@@ -8866,6 +8915,14 @@ interface PreflightOrchestratorSpec {
|
|
|
8866
8915
|
model?: ModelSpec;
|
|
8867
8916
|
limits?: UsageLimits;
|
|
8868
8917
|
estInputTokens?: number;
|
|
8918
|
+
/**
|
|
8919
|
+
* Mirrors OrchestrateSynthesis.exposeChildResultTools (the v1.74
|
|
8920
|
+
* experiment review, P0.2): declaring it lets the evidence
|
|
8921
|
+
* asymmetry check see that the synthesis model can page the full
|
|
8922
|
+
* child outputs the validators judge against.
|
|
8923
|
+
*/
|
|
8924
|
+
exposeChildResultTools?: boolean; /** Mirrors OrchestrateSynthesis.context; default 'digests'. */
|
|
8925
|
+
context?: "digests" | "full";
|
|
8869
8926
|
};
|
|
8870
8927
|
}
|
|
8871
8928
|
/** The full input: engine surface, run surface, and the declared wave. */
|
package/dist/index.js
CHANGED
|
@@ -15879,6 +15879,19 @@ function validateOrchestrateOptions(opts) {
|
|
|
15879
15879
|
}
|
|
15880
15880
|
if (fv.maxRepairs !== void 0) requireNonNegativeInteger(fv.maxRepairs, "orchestrate finishValidation.maxRepairs");
|
|
15881
15881
|
if (fv.repairTurnReserve !== void 0) requireNonNegativeInteger(fv.repairTurnReserve, "orchestrate finishValidation.repairTurnReserve");
|
|
15882
|
+
const draftPolicy = fv.draftPolicy;
|
|
15883
|
+
if (draftPolicy !== void 0) {
|
|
15884
|
+
if (typeof draftPolicy !== "object" || draftPolicy === null) throw new ConfigError("orchestrate finishValidation.draftPolicy must be an object");
|
|
15885
|
+
if (opts.synthesis === void 0) throw new ConfigError("orchestrate finishValidation.draftPolicy requires synthesis: without a synthesis invocation the validators bind the coordination finish itself and there is no unvalidated draft to gate");
|
|
15886
|
+
const policy = draftPolicy;
|
|
15887
|
+
if (policy.minWords === void 0 && policy.requireSections === void 0) throw new ConfigError("orchestrate finishValidation.draftPolicy must declare minWords, requireSections, or both");
|
|
15888
|
+
if (policy.minWords !== void 0) {
|
|
15889
|
+
if (typeof policy.minWords !== "number" || !Number.isInteger(policy.minWords) || policy.minWords < 1) throw new ConfigError(`orchestrate finishValidation.draftPolicy.minWords must be a positive integer; got ${JSON.stringify(policy.minWords)}`);
|
|
15890
|
+
}
|
|
15891
|
+
if (policy.requireSections !== void 0) {
|
|
15892
|
+
if (!Array.isArray(policy.requireSections) || policy.requireSections.length === 0 || policy.requireSections.some((section) => typeof section !== "string" || section.length === 0)) throw new ConfigError("orchestrate finishValidation.draftPolicy.requireSections must be a non empty array of non empty strings");
|
|
15893
|
+
}
|
|
15894
|
+
}
|
|
15882
15895
|
const contract = fv.contract;
|
|
15883
15896
|
if (contract !== void 0) {
|
|
15884
15897
|
const shape = contract;
|
|
@@ -15904,6 +15917,9 @@ function validateOrchestrateOptions(opts) {
|
|
|
15904
15917
|
if (synthesis.mode !== void 0 && synthesis.mode !== "single" && synthesis.mode !== "incremental") throw new ConfigError("orchestrate synthesis.mode must be 'single' or 'incremental'; got " + JSON.stringify(synthesis.mode));
|
|
15905
15918
|
if (synthesis.mode === "incremental" && opts.finishValidation !== void 0) throw new ConfigError("orchestrate synthesis.mode 'incremental' reconciles deterministically and has no model-composed final finish for finishValidation to bind; configure validators with mode 'single', or drop them");
|
|
15906
15919
|
if (synthesis.dedupeClaims !== void 0 && typeof synthesis.dedupeClaims !== "boolean") throw new ConfigError("orchestrate synthesis.dedupeClaims must be a boolean; got " + typeof synthesis.dedupeClaims);
|
|
15920
|
+
const symmetry = synthesis;
|
|
15921
|
+
if (symmetry.exposeChildResultTools !== void 0 && typeof symmetry.exposeChildResultTools !== "boolean") throw new ConfigError("orchestrate synthesis.exposeChildResultTools must be a boolean; got " + typeof symmetry.exposeChildResultTools);
|
|
15922
|
+
if (symmetry.context !== void 0 && symmetry.context !== "digests" && symmetry.context !== "full") throw new ConfigError("orchestrate synthesis.context must be 'digests' or 'full'; got " + JSON.stringify(symmetry.context));
|
|
15907
15923
|
if (synthesis.noteLimits !== void 0) validateUsageLimits(synthesis.noteLimits, "orchestrate synthesis.noteLimits");
|
|
15908
15924
|
if (synthesis.effort !== void 0 && ![
|
|
15909
15925
|
"low",
|
|
@@ -16940,6 +16956,37 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
16940
16956
|
};
|
|
16941
16957
|
};
|
|
16942
16958
|
/**
|
|
16959
|
+
* The coordination draft gate (the v1.74 experiment review, P0.3):
|
|
16960
|
+
* deterministic library text checks over the draft finish, run only
|
|
16961
|
+
* when the validators bind synthesis. Unlike validateFinish nothing
|
|
16962
|
+
* journals: the checks are pure functions of the exchange, the
|
|
16963
|
+
* rejected exchange is durable in the transcript itself, and a
|
|
16964
|
+
* resumed segment recounts identically. The rejection is the finish
|
|
16965
|
+
* call's error result, so the loop's repair-reserve grants count it
|
|
16966
|
+
* exactly like a host validation rejection.
|
|
16967
|
+
*/
|
|
16968
|
+
const validateDraft = (call) => {
|
|
16969
|
+
const policy = validationSpec?.draftPolicy;
|
|
16970
|
+
if (policy === void 0) return Promise.resolve({ ok: true });
|
|
16971
|
+
const result = call.result ?? null;
|
|
16972
|
+
const text = typeof result === "string" ? result : JSON.stringify(result);
|
|
16973
|
+
const reasons = [];
|
|
16974
|
+
if (policy.minWords !== void 0) {
|
|
16975
|
+
const trimmed = text.trim();
|
|
16976
|
+
const words = trimmed === "" ? 0 : trimmed.split(/\s+/).length;
|
|
16977
|
+
if (words < policy.minWords) reasons.push(`the draft carries ${String(words)} words, below the required ${String(policy.minWords)}`);
|
|
16978
|
+
}
|
|
16979
|
+
for (const section of policy.requireSections ?? []) if (!text.includes(section)) reasons.push(`required draft section '${section}' is missing`);
|
|
16980
|
+
if (reasons.length === 0) return Promise.resolve({ ok: true });
|
|
16981
|
+
return Promise.resolve({
|
|
16982
|
+
ok: false,
|
|
16983
|
+
feedback: {
|
|
16984
|
+
error: "the coordination draft failed the draft policy; repair the draft and call finish again: the synthesis invocation composes the FINAL result from this draft, and a collapsed draft starves it of the evidence the validators demand",
|
|
16985
|
+
reasons
|
|
16986
|
+
}
|
|
16987
|
+
});
|
|
16988
|
+
};
|
|
16989
|
+
/**
|
|
16943
16990
|
* The frozen bundle descriptor (the v1.71 experiment review,
|
|
16944
16991
|
* P0.2): with a contract configured, the run durably records WHAT
|
|
16945
16992
|
* validates it. One decision entry per distinct contract hash, in
|
|
@@ -16984,7 +17031,10 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
16984
17031
|
},
|
|
16985
17032
|
[kTerminalTool]: {
|
|
16986
17033
|
name: FINISH_TOOL_NAME,
|
|
16987
|
-
...validationSpec === void 0 || opts?.synthesis !== void 0 ?
|
|
17034
|
+
...validationSpec === void 0 || opts?.synthesis !== void 0 ? validationSpec?.draftPolicy !== void 0 && opts?.synthesis !== void 0 ? {
|
|
17035
|
+
validate: validateDraft,
|
|
17036
|
+
...validationSpec.repairTurnReserve === void 0 ? {} : { repairTurnReserve: validationSpec.repairTurnReserve }
|
|
17037
|
+
} : {} : {
|
|
16988
17038
|
validate: validateFinish,
|
|
16989
17039
|
...validationSpec.repairTurnReserve === void 0 ? {} : { repairTurnReserve: validationSpec.repairTurnReserve }
|
|
16990
17040
|
}
|
|
@@ -17229,8 +17279,15 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
17229
17279
|
if (spec === void 0) return draft;
|
|
17230
17280
|
await recoveryDone;
|
|
17231
17281
|
if (spec.mode === "incremental") return await reconcileIncremental(draft, spec);
|
|
17232
|
-
const
|
|
17233
|
-
const
|
|
17282
|
+
const exposeTools = spec.exposeChildResultTools === true;
|
|
17283
|
+
const fullContext = spec.context === "full";
|
|
17284
|
+
const synthesisToolNames = /* @__PURE__ */ new Set([FINISH_TOOL_NAME, ...exposeTools ? [GET_CHILD_RESULT_TOOL_NAME, READ_CHILD_ARTIFACT_TOOL_NAME] : []]);
|
|
17285
|
+
const synthesisTools = buildOrchestratorTools(orchestratorRuntime, fullCardText, { childResultTools: exposeTools }).filter((tool) => synthesisToolNames.has(tool.name));
|
|
17286
|
+
const settledEntries = [...records.entries()].filter((entry) => entry[1].settled !== void 0).sort((a, b) => a[1].spawnOrdinal - b[1].spawnOrdinal);
|
|
17287
|
+
const settledDigests = settledEntries.map(([handle, record]) => ({
|
|
17288
|
+
...exposeTools ? { handle } : {},
|
|
17289
|
+
...digestOf(record, record.settled)
|
|
17290
|
+
}));
|
|
17234
17291
|
let digestRows = settledDigests;
|
|
17235
17292
|
let repeatedClaims;
|
|
17236
17293
|
if (spec.dedupeClaims === true) {
|
|
@@ -17248,13 +17305,19 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
17248
17305
|
const draftJson = JSON.stringify(draft ?? null);
|
|
17249
17306
|
const digestJson = JSON.stringify(digestRows);
|
|
17250
17307
|
const prompt = [
|
|
17251
|
-
"You are the synthesis invocation of an orchestrated run. Compose the FINAL result of the run from the goal, the coordination draft, and the settled child evidence below by calling finish({ result }) EXACTLY once. Preserve the evidence and citations the draft relies on; do not invent findings. No other tool exists.",
|
|
17308
|
+
"You are the synthesis invocation of an orchestrated run. Compose the FINAL result of the run from the goal, the coordination draft, and the settled child evidence below by calling finish({ result }) EXACTLY once. Preserve the evidence and citations the draft relies on; do not invent findings. " + (exposeTools ? "Beside finish, get_child_result and read_child_artifact page any SETTLED child's FULL output and artifacts by handle (each DIGEST row carries its handle); read what the validators will hold you to before finishing." : "No other tool exists."),
|
|
17252
17309
|
...repeatedClaims === void 0 ? [] : ["Repeated claims across children were deduplicated before this prompt: only the first occurrence of each repeated line remains in the digest, and the REPEATED CLAIMS index below lists each one with its reporters."],
|
|
17253
17310
|
...spec.instructions === void 0 ? [] : [spec.instructions],
|
|
17254
17311
|
...finishValidationPromptLines(validationSpec),
|
|
17255
17312
|
`GOAL: ${goal}`,
|
|
17256
17313
|
`DRAFT: ${draftJson}`,
|
|
17257
17314
|
`DIGEST: ${digestJson}`,
|
|
17315
|
+
...fullContext ? [`CHILD OUTPUTS: ${JSON.stringify(settledEntries.map(([handle, record]) => ({
|
|
17316
|
+
...exposeTools ? { handle } : {},
|
|
17317
|
+
nodeId: record.nodeId,
|
|
17318
|
+
status: record.settled.status,
|
|
17319
|
+
text: serializeChildOutput(record.settled)
|
|
17320
|
+
})))}`] : [],
|
|
17258
17321
|
...repeatedClaims === void 0 ? [] : [`REPEATED CLAIMS: ${JSON.stringify(repeatedClaims)}`]
|
|
17259
17322
|
].join("\n");
|
|
17260
17323
|
internals.events.emit({
|
|
@@ -17280,7 +17343,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
17280
17343
|
const synthesisOpts = {
|
|
17281
17344
|
role: "synthesize",
|
|
17282
17345
|
result: "full",
|
|
17283
|
-
tools:
|
|
17346
|
+
tools: synthesisTools,
|
|
17284
17347
|
limits: spec.limits ?? { maxTurns: 4 },
|
|
17285
17348
|
...spec.model === void 0 ? {} : { model: spec.model },
|
|
17286
17349
|
...spec.effort === void 0 ? {} : { effort: spec.effort },
|
|
@@ -17895,6 +17958,21 @@ function preflightEstimate(input) {
|
|
|
17895
17958
|
const synthesis = input.orchestrator.synthesis;
|
|
17896
17959
|
if (synthesis.limits !== void 0) validateUsageLimits(synthesis.limits, "preflight orchestrator.synthesis.limits");
|
|
17897
17960
|
if (synthesis.estInputTokens !== void 0) requireNonNegativeInteger(synthesis.estInputTokens, "preflight orchestrator.synthesis.estInputTokens");
|
|
17961
|
+
if (synthesis.context !== void 0 && synthesis.context !== "digests" && synthesis.context !== "full") throw new ConfigError("preflight orchestrator.synthesis.context must be 'digests' or 'full'; got " + JSON.stringify(synthesis.context));
|
|
17962
|
+
{
|
|
17963
|
+
const evidenceNames = /* @__PURE__ */ new Set([
|
|
17964
|
+
"evidence-preserved",
|
|
17965
|
+
"contract-citations",
|
|
17966
|
+
"contract-section-citations"
|
|
17967
|
+
]);
|
|
17968
|
+
const evidenceValidators = (input.finishValidation?.validators ?? []).map((validator) => validator.name).filter((name) => evidenceNames.has(name));
|
|
17969
|
+
if ((evidenceValidators.length > 0 || input.finishValidation?.contract?.manifest.citations !== void 0) && synthesis.exposeChildResultTools !== true && (synthesis.context ?? "digests") === "digests") say({
|
|
17970
|
+
severity: "warning",
|
|
17971
|
+
code: "synthesis-evidence-asymmetry",
|
|
17972
|
+
message: `the finish validators demand child evidence (${evidenceValidators.length > 0 ? evidenceValidators.join(", ") : "contract citations"}) but the synthesis invocation sees only truncated digest rows and has no child read tools: a collapsed coordination draft starves it of every citation (the v1.74 experiment shape); set synthesis.exposeChildResultTools, synthesis.context 'full', or bind the validators to coordination by dropping synthesis`,
|
|
17973
|
+
spawn: "synthesis"
|
|
17974
|
+
});
|
|
17975
|
+
}
|
|
17898
17976
|
const servedBy = resolveServing(synthesis.model) ?? resolveServing(defaults.routing?.synthesize);
|
|
17899
17977
|
if (servedBy === void 0) say({
|
|
17900
17978
|
severity: "error",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.76.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",
|