@orkestrel/study 0.0.1 → 0.0.3
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/README.md +63 -1
- package/dist/bin/main.js +2 -5399
- package/dist/bin/main.js.map +1 -1
- package/dist/src/core/index.cjs +105 -19
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +83 -12
- package/dist/src/core/index.d.ts +83 -12
- package/dist/src/core/index.js +104 -21
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +3941 -3595
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +1018 -451
- package/dist/src/server/index.d.ts +1018 -451
- package/dist/src/server/index.js +3115 -2823
- package/dist/src/server/index.js.map +1 -1
- package/package.json +18 -9
package/dist/src/core/index.cjs
CHANGED
|
@@ -8,8 +8,8 @@ let _orkestrel_abort = require("@orkestrel/abort");
|
|
|
8
8
|
* Keys the own self-identity every study error stamps on itself.
|
|
9
9
|
* @remarks
|
|
10
10
|
* The global symbol registry lets every package, ESM, CommonJS and captured copy read the same
|
|
11
|
-
* key. The registry makes the key discoverable; it
|
|
12
|
-
*
|
|
11
|
+
* key. The registry makes the key discoverable; it recognizes the contract without proving
|
|
12
|
+
* its origin.
|
|
13
13
|
*/
|
|
14
14
|
var STUDY_ERROR_BRAND = Symbol.for("@orkestrel/study.error");
|
|
15
15
|
/** Caps a declared trial population before schedule allocation. */
|
|
@@ -24,6 +24,7 @@ var STUDY_ROLES = Object.freeze([
|
|
|
24
24
|
"judge",
|
|
25
25
|
"summary",
|
|
26
26
|
"metadata",
|
|
27
|
+
"maintenance",
|
|
27
28
|
"tool"
|
|
28
29
|
]);
|
|
29
30
|
/** Lists every ceiling a run can stop at in report order. */
|
|
@@ -67,16 +68,18 @@ function omitStudyAbsent(value) {
|
|
|
67
68
|
* ```
|
|
68
69
|
*/
|
|
69
70
|
function normalizeStudyProfile(profile) {
|
|
70
|
-
const { provider, qualification, settings, room, ...required } = profile;
|
|
71
|
+
const { provider, qualification, settings, record, room, ...required } = profile;
|
|
71
72
|
return {
|
|
72
73
|
...required,
|
|
73
74
|
room: omitStudyAbsent(room),
|
|
74
75
|
...provider === void 0 ? {} : { provider: {
|
|
75
76
|
...omitStudyAbsent(provider),
|
|
76
|
-
digest: omitStudyAbsent(provider.digest)
|
|
77
|
+
digest: omitStudyAbsent(provider.digest),
|
|
78
|
+
...provider.daemon === void 0 ? {} : { daemon: omitStudyAbsent(provider.daemon) }
|
|
77
79
|
} },
|
|
78
80
|
...qualification === void 0 ? {} : { qualification },
|
|
79
|
-
...settings === void 0 ? {} : { settings }
|
|
81
|
+
...settings === void 0 ? {} : { settings },
|
|
82
|
+
...record === void 0 ? {} : { record }
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
/**
|
|
@@ -150,7 +153,7 @@ function buildStudySchedule(definition, scenarios) {
|
|
|
150
153
|
* @param rubric - The independently held grading declaration
|
|
151
154
|
* @param profile - The execution bounds and model room
|
|
152
155
|
* @returns Nothing when every cross-input invariant holds
|
|
153
|
-
* @throws StudyError - Thrown when any input or cross-reference is invalid
|
|
156
|
+
* @throws StudyError - Thrown when any input or cross-reference is invalid, or a quality study has no capacity qualification
|
|
154
157
|
* @example
|
|
155
158
|
* ```ts
|
|
156
159
|
* validateStudyInputs(definition, scenarios, rubric, profile)
|
|
@@ -167,6 +170,7 @@ function validateStudyInputs(definition, scenarios, rubric, profile) {
|
|
|
167
170
|
}
|
|
168
171
|
const covered = new Set(rubric.criteria.map((criterion) => (0, _orkestrel_contract.canonicalStringify)([criterion.scenario, criterion.goal]) ?? ""));
|
|
169
172
|
for (const scenario of scenarios) for (const goal of scenario.goals) if (!covered.has((0, _orkestrel_contract.canonicalStringify)([scenario.id, goal.id]) ?? "")) throw new StudyError("CONFIG", "Every declared goal needs a criterion");
|
|
173
|
+
if (definition.purpose === "quality" && profile.qualification === void 0) throw new StudyError("CONFIG", "Quality studies require a capacity qualification");
|
|
170
174
|
}
|
|
171
175
|
/**
|
|
172
176
|
* Computes arm intervals over the complete declared criterion horizon.
|
|
@@ -417,15 +421,46 @@ function isStudyProvider(value) {
|
|
|
417
421
|
"url",
|
|
418
422
|
"model",
|
|
419
423
|
"digest"
|
|
420
|
-
], ["judge"]) || ![
|
|
424
|
+
], ["judge", "daemon"]) || ![
|
|
421
425
|
"entry",
|
|
422
426
|
"url",
|
|
423
427
|
"model"
|
|
424
428
|
].every((key) => (0, _orkestrel_contract.isNonEmptyString)(value[key])) || typeof value.url !== "string" || !(0, _orkestrel_contract.isRecord)(value.digest) || !matchesStudyKeys(value.digest, ["model"], ["judge"]) || !isStudyDigest(value.digest.model) || value.judge === void 0 !== (value.digest.judge === void 0) || value.judge !== void 0 && (!(0, _orkestrel_contract.isNonEmptyString)(value.judge) || !isStudyDigest(value.digest.judge))) return false;
|
|
425
429
|
const url = new URL(value.url);
|
|
430
|
+
if (value.daemon !== void 0) {
|
|
431
|
+
if (!isStudyDaemon(value.daemon) || !/^http:\/\/127\.0\.0\.1:[0-9]+\/?$/.test(value.url) || Number(url.port) <= 0 || Number(url.port) === 11434) return false;
|
|
432
|
+
const daemon = value.daemon;
|
|
433
|
+
const digest = value.digest;
|
|
434
|
+
if (!daemon.models.every((model) => model.name === value.model && model.digest === digest.model || value.judge !== void 0 && model.name === value.judge && model.digest === digest.judge) || !daemon.models.some((model) => model.name === value.model && model.digest === digest.model) || value.judge !== void 0 && !daemon.models.some((model) => model.name === value.judge && model.digest === digest.judge)) return false;
|
|
435
|
+
}
|
|
426
436
|
return ["http:", "https:"].includes(url.protocol) && url.username === "" && url.password === "" && url.search === "" && url.hash === "" && url.pathname === "/";
|
|
427
437
|
});
|
|
428
438
|
}
|
|
439
|
+
/** Checks whether an owned daemon declaration pins an absolute executable and distinct models.
|
|
440
|
+
* @param value - The candidate declaration.
|
|
441
|
+
* @returns True if executable, version, environment, and model identities are valid; false otherwise.
|
|
442
|
+
* @example
|
|
443
|
+
* ```ts
|
|
444
|
+
* isStudyDaemon({ executable: 'ollama' }) // false
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
function isStudyDaemon(value) {
|
|
448
|
+
return (0, _orkestrel_contract.holds)(() => {
|
|
449
|
+
if (!(0, _orkestrel_contract.isRecord)(value) || !matchesStudyKeys(value, [
|
|
450
|
+
"executable",
|
|
451
|
+
"digest",
|
|
452
|
+
"version",
|
|
453
|
+
"models"
|
|
454
|
+
], ["environment"]) || typeof value.executable !== "string" || !/^(?:[A-Za-z]:[\\/]|\/(?!\/)|\\\\[^\\]+\\[^\\]+\\)/.test(value.executable) || value.executable.includes("\0") || value.executable.split(/[\\/]/).some((part) => part === "." || part === "..") || !isStudyDigest(value.digest) || !(0, _orkestrel_contract.isNonEmptyString)(value.version) || value.version.trim().length === 0 || value.version.includes("\0") || !(0, _orkestrel_contract.isArray)(value.models) || value.models.length === 0 || !value.models.every((model) => (0, _orkestrel_contract.isRecord)(model) && matchesStudyKeys(model, ["name", "digest"]) && (0, _orkestrel_contract.isNonEmptyString)(model.name) && model.name.trim().length > 0 && !model.name.includes("\0") && isStudyDigest(model.digest))) return false;
|
|
455
|
+
if (new Set(value.models.map((model) => (0, _orkestrel_contract.isRecord)(model) ? model.name : void 0)).size !== value.models.length) return false;
|
|
456
|
+
if (value.environment !== void 0) {
|
|
457
|
+
if (!(0, _orkestrel_contract.isRecord)(value.environment) || !matchesStudyKeys(value.environment, [], Object.keys(value.environment))) return false;
|
|
458
|
+
const entries = Object.entries(value.environment);
|
|
459
|
+
if (new Set(entries.map(([name]) => name.toLowerCase())).size !== entries.length || entries.some(([name, entry]) => name.length === 0 || /[=\0]/.test(name) || typeof entry !== "string" || entry.includes("\0"))) return false;
|
|
460
|
+
}
|
|
461
|
+
return true;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
429
464
|
/**
|
|
430
465
|
* Checks whether a profile carries finite bounds and an optional explicit provider.
|
|
431
466
|
* @param value - The candidate profile
|
|
@@ -447,10 +482,18 @@ function isStudyProfile(value) {
|
|
|
447
482
|
], [
|
|
448
483
|
"provider",
|
|
449
484
|
"qualification",
|
|
450
|
-
"settings"
|
|
451
|
-
|
|
485
|
+
"settings",
|
|
486
|
+
"record"
|
|
487
|
+
]) && isStudyName(value.name) && (0, _orkestrel_contract.isNonEmptyString)(value.agent) && (0, _orkestrel_contract.isArray)(value.roots) && (0, _orkestrel_contract.isJSONValue)(value.roots) && value.roots.length > 0 && value.roots.every((root) => typeof root === "string" && root.trim().length > 0) && new Set(value.roots).size === value.roots.length && (0, _orkestrel_contract.isNonEmptyString)(value.subject) && isStudyBounds(value.bounds) && isStudyRoom(value.room) && (value.provider === void 0 || isStudyProvider(value.provider)) && (value.record === void 0 || isStudyRecord(value.record)) && (value.qualification === void 0 || (0, _orkestrel_contract.isNonEmptyString)(value.qualification)) && (value.settings === void 0 || (0, _orkestrel_contract.isRecord)(value.settings) && (0, _orkestrel_contract.isJSONValue)(value.settings));
|
|
452
488
|
});
|
|
453
489
|
}
|
|
490
|
+
/** Checks whether a recording declaration bounds every serialized sidecar byte.
|
|
491
|
+
* @param value - The candidate declaration.
|
|
492
|
+
* @returns True if its byte allowance is a positive safe integer; false otherwise.
|
|
493
|
+
*/
|
|
494
|
+
function isStudyRecord(value) {
|
|
495
|
+
return (0, _orkestrel_contract.holds)(() => (0, _orkestrel_contract.isRecord)(value) && matchesStudyKeys(value, ["bytes"]) && typeof value.bytes === "number" && Number.isSafeInteger(value.bytes) && value.bytes > 0);
|
|
496
|
+
}
|
|
454
497
|
/**
|
|
455
498
|
* Checks whether a byte identity is a lowercase SHA-256 digest.
|
|
456
499
|
* @param value - The candidate identity
|
|
@@ -631,8 +674,10 @@ var StudyError = class extends Error {
|
|
|
631
674
|
*/
|
|
632
675
|
constructor(code, message, failure) {
|
|
633
676
|
super(message);
|
|
634
|
-
|
|
677
|
+
_orkestrel_contract.INTRINSICS.define(this, STUDY_ERROR_BRAND, {
|
|
635
678
|
value: this,
|
|
679
|
+
enumerable: false,
|
|
680
|
+
writable: false,
|
|
636
681
|
configurable: true
|
|
637
682
|
});
|
|
638
683
|
this.name = "StudyError";
|
|
@@ -641,14 +686,15 @@ var StudyError = class extends Error {
|
|
|
641
686
|
}
|
|
642
687
|
};
|
|
643
688
|
/**
|
|
644
|
-
* Narrows a caught value to
|
|
689
|
+
* Narrows a caught value to a branded study error with valid failure attribution.
|
|
645
690
|
* @remarks
|
|
646
|
-
* Recognition combines the native `Error` base, a subclass prototype,
|
|
647
|
-
*
|
|
691
|
+
* Recognition combines the native `Error` base, a subclass prototype, a declared study code,
|
|
692
|
+
* valid optional failure members, and an own {@link STUDY_ERROR_BRAND} descriptor whose value is
|
|
693
|
+
* the error itself. Subclasses can replace the name.
|
|
648
694
|
* The global key is recognized across package, ESM, CommonJS and captured module copies; it is
|
|
649
|
-
* not
|
|
695
|
+
* not proof of origin. A transparent proxy is refused because its forwarded descriptor
|
|
650
696
|
* stores the target, and an unbranded copy, an inherited brand, or a property-only lookalike
|
|
651
|
-
* stays outside the type.
|
|
697
|
+
* stays outside the type. Throwing property access returns false instead of throwing.
|
|
652
698
|
* @param value - The caught value
|
|
653
699
|
* @returns True if the value is a study error; false otherwise
|
|
654
700
|
* @example
|
|
@@ -657,7 +703,28 @@ var StudyError = class extends Error {
|
|
|
657
703
|
* ```
|
|
658
704
|
*/
|
|
659
705
|
function isStudyError(value) {
|
|
660
|
-
return (0, _orkestrel_contract.
|
|
706
|
+
return (0, _orkestrel_contract.holds)(() => {
|
|
707
|
+
if (!(value instanceof _orkestrel_contract.INTRINSICS.error) || _orkestrel_contract.INTRINSICS.prototype(value) === _orkestrel_contract.INTRINSICS.error.prototype) return false;
|
|
708
|
+
const brand = _orkestrel_contract.INTRINSICS.describe(value, STUDY_ERROR_BRAND)?.value;
|
|
709
|
+
const code = _orkestrel_contract.INTRINSICS.reflect.read(value, "code");
|
|
710
|
+
const failure = _orkestrel_contract.INTRINSICS.reflect.read(value, "failure");
|
|
711
|
+
const stack = _orkestrel_contract.INTRINSICS.reflect.read(value, "stack");
|
|
712
|
+
if (brand !== value || !isStudyErrorCode(code) || typeof _orkestrel_contract.INTRINSICS.reflect.read(value, "name") !== "string" || typeof _orkestrel_contract.INTRINSICS.reflect.read(value, "message") !== "string" || stack !== void 0 && typeof stack !== "string") return false;
|
|
713
|
+
if (failure === void 0) return true;
|
|
714
|
+
if (!(0, _orkestrel_contract.isObject)(failure)) return false;
|
|
715
|
+
const cause = _orkestrel_contract.INTRINSICS.reflect.read(failure, "cause");
|
|
716
|
+
const message = _orkestrel_contract.INTRINSICS.reflect.read(failure, "message");
|
|
717
|
+
const role = _orkestrel_contract.INTRINSICS.reflect.read(failure, "role");
|
|
718
|
+
const stop = _orkestrel_contract.INTRINSICS.reflect.read(failure, "stop");
|
|
719
|
+
if (!isStudyCause(cause) || typeof message !== "string" || role !== void 0 && !isStudyRole(role)) return false;
|
|
720
|
+
if (stop === void 0) return true;
|
|
721
|
+
if (!(0, _orkestrel_contract.isObject)(stop)) return false;
|
|
722
|
+
const layer = _orkestrel_contract.INTRINSICS.reflect.read(stop, "layer");
|
|
723
|
+
const id = _orkestrel_contract.INTRINSICS.reflect.read(stop, "id");
|
|
724
|
+
const max = _orkestrel_contract.INTRINSICS.reflect.read(stop, "max");
|
|
725
|
+
const consumed = _orkestrel_contract.INTRINSICS.reflect.read(stop, "consumed");
|
|
726
|
+
return isStudyLayer(layer) && typeof id === "string" && (max === void 0 || (0, _orkestrel_contract.isNumber)(max)) && (consumed === void 0 || (0, _orkestrel_contract.isNumber)(consumed));
|
|
727
|
+
});
|
|
661
728
|
}
|
|
662
729
|
//#endregion
|
|
663
730
|
//#region src/core/parsers.ts
|
|
@@ -921,8 +988,8 @@ function computeStudyOutputStop(bytes, limit, outputs) {
|
|
|
921
988
|
};
|
|
922
989
|
}
|
|
923
990
|
/**
|
|
924
|
-
* Records an error
|
|
925
|
-
* @param ticket - The admitted request whose work
|
|
991
|
+
* Records an error thrown by admitted work as the failure of its ticket.
|
|
992
|
+
* @param ticket - The admitted request whose work threw
|
|
926
993
|
* @param error - The caught value, read through `readStudyFailure`
|
|
927
994
|
* @param role - The responsibility that replaces any role the reading carries; Default: the carried role, else the ticket's admitted role
|
|
928
995
|
* @remarks
|
|
@@ -931,7 +998,7 @@ function computeStudyOutputStop(bytes, limit, outputs) {
|
|
|
931
998
|
* so the parent's ownership is respected rather than inferred as local settlement. A refusal
|
|
932
999
|
* thrown by the ticket's own settlement propagates.
|
|
933
1000
|
* @throws Thrown when the ticket's settlement refuses the failure.
|
|
934
|
-
* @example Fail an
|
|
1001
|
+
* @example Fail an admitted request
|
|
935
1002
|
* ```ts
|
|
936
1003
|
* import type { StudyTicket } from '@orkestrel/study'
|
|
937
1004
|
* import { failStudyTicket } from '@orkestrel/study'
|
|
@@ -1877,6 +1944,22 @@ function buildStudyAgentDispatch(dispatch) {
|
|
|
1877
1944
|
//#endregion
|
|
1878
1945
|
//#region src/core/agents/validators.ts
|
|
1879
1946
|
/**
|
|
1947
|
+
* Checks whether a value is a gauge with a finite positive scale and a finite nonnegative overhead.
|
|
1948
|
+
* @param value - The candidate gauge; additional members are admitted
|
|
1949
|
+
* @returns True if the gauge readings are finite and within their bounds; false otherwise
|
|
1950
|
+
* @example
|
|
1951
|
+
* ```ts
|
|
1952
|
+
* isStudyAgentGauge({ scale: 1, overhead: 0 }) // true
|
|
1953
|
+
* ```
|
|
1954
|
+
*/
|
|
1955
|
+
function isStudyAgentGauge(value) {
|
|
1956
|
+
return (0, _orkestrel_contract.holds)(() => {
|
|
1957
|
+
if (!(0, _orkestrel_contract.isObject)(value) || !("scale" in value) || !("overhead" in value)) return false;
|
|
1958
|
+
const { scale, overhead } = value;
|
|
1959
|
+
return (0, _orkestrel_contract.isFiniteNumber)(scale) && scale > 0 && (0, _orkestrel_contract.isFiniteNumber)(overhead) && overhead >= 0;
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1880
1963
|
* Checks whether a namespace exposes the Agent capabilities the instrumentation invokes.
|
|
1881
1964
|
* @remarks
|
|
1882
1965
|
* The guard reads only `estimateRequest`, `measureRequest`, and `isAgentError`, so a namespace
|
|
@@ -2020,10 +2103,12 @@ exports.computeStudyOutputStop = computeStudyOutputStop;
|
|
|
2020
2103
|
exports.computeStudyScores = computeStudyScores;
|
|
2021
2104
|
exports.failStudyTicket = failStudyTicket;
|
|
2022
2105
|
exports.failureToStudyError = failureToStudyError;
|
|
2106
|
+
exports.isStudyAgentGauge = isStudyAgentGauge;
|
|
2023
2107
|
exports.isStudyAgentRuntime = isStudyAgentRuntime;
|
|
2024
2108
|
exports.isStudyBounds = isStudyBounds;
|
|
2025
2109
|
exports.isStudyCause = isStudyCause;
|
|
2026
2110
|
exports.isStudyCriterion = isStudyCriterion;
|
|
2111
|
+
exports.isStudyDaemon = isStudyDaemon;
|
|
2027
2112
|
exports.isStudyDefinition = isStudyDefinition;
|
|
2028
2113
|
exports.isStudyDigest = isStudyDigest;
|
|
2029
2114
|
exports.isStudyError = isStudyError;
|
|
@@ -2038,6 +2123,7 @@ exports.isStudyName = isStudyName;
|
|
|
2038
2123
|
exports.isStudyProduct = isStudyProduct;
|
|
2039
2124
|
exports.isStudyProfile = isStudyProfile;
|
|
2040
2125
|
exports.isStudyProvider = isStudyProvider;
|
|
2126
|
+
exports.isStudyRecord = isStudyRecord;
|
|
2041
2127
|
exports.isStudyRole = isStudyRole;
|
|
2042
2128
|
exports.isStudyRoom = isStudyRoom;
|
|
2043
2129
|
exports.isStudyRubric = isStudyRubric;
|