@openpond/evals 0.7.6 → 0.8.1
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/LEARNING.md +30 -0
- package/dist/learning/authoring-service.js +1 -1
- package/dist/learning/authoring.js +9 -0
- package/dist/learning/contracts.js +10 -0
- package/dist/learning/index.js +4 -0
- package/dist/learning/operations.js +3 -1
- package/dist/learning/repository.js +2 -0
- package/dist/learning/reward-authoring.js +120 -0
- package/dist/learning/reward-check-service.js +31 -0
- package/dist/learning/reward-check-worker.js +114 -0
- package/dist/learning/reward-checks.js +81 -0
- package/dist/learning/reward-fixture-executor.js +29 -0
- package/dist/learning/service.js +7 -0
- package/dist/rewards.js +3 -0
- package/dist/types/learning/admission.d.ts +12 -0
- package/dist/types/learning/admission.d.ts.map +1 -1
- package/dist/types/learning/authoring-service.d.ts +172 -0
- package/dist/types/learning/authoring-service.d.ts.map +1 -1
- package/dist/types/learning/authoring.d.ts +121 -0
- package/dist/types/learning/authoring.d.ts.map +1 -1
- package/dist/types/learning/contracts.d.ts +90 -0
- package/dist/types/learning/contracts.d.ts.map +1 -1
- package/dist/types/learning/index.d.ts +4 -0
- package/dist/types/learning/index.d.ts.map +1 -1
- package/dist/types/learning/operations.d.ts +204 -0
- package/dist/types/learning/operations.d.ts.map +1 -1
- package/dist/types/learning/repository.d.ts +129 -1
- package/dist/types/learning/repository.d.ts.map +1 -1
- package/dist/types/learning/reward-authoring.d.ts +18 -0
- package/dist/types/learning/reward-authoring.d.ts.map +1 -0
- package/dist/types/learning/reward-check-service.d.ts +17 -0
- package/dist/types/learning/reward-check-service.d.ts.map +1 -0
- package/dist/types/learning/reward-check-worker.d.ts +27 -0
- package/dist/types/learning/reward-check-worker.d.ts.map +1 -0
- package/dist/types/learning/reward-checks.d.ts +177 -0
- package/dist/types/learning/reward-checks.d.ts.map +1 -0
- package/dist/types/learning/reward-fixture-executor.d.ts +9 -0
- package/dist/types/learning/reward-fixture-executor.d.ts.map +1 -0
- package/dist/types/learning/service.d.ts.map +1 -1
- package/dist/types/learning/transport.d.ts +232 -3
- package/dist/types/learning/transport.d.ts.map +1 -1
- package/dist/types/rewards.d.ts +24 -0
- package/dist/types/rewards.d.ts.map +1 -1
- package/package.json +1 -1
- package/schemas/learning/v1/command-request.schema.json +443 -248
- package/schemas/learning/v1/draft.schema.json +96 -0
- package/schemas/learning/v1/read-request.schema.json +1 -0
- package/schemas/learning/v1/reward.schema.json +3 -0
- package/schemas/learning/v1/reward_check.schema.json +343 -0
- package/schemas/learning/v1/source.schema.json +64 -33
package/LEARNING.md
CHANGED
|
@@ -79,6 +79,36 @@ for untrusted schemas and deliberately rejects unsupported capabilities.
|
|
|
79
79
|
|
|
80
80
|
## Host responsibilities
|
|
81
81
|
|
|
82
|
+
### Reward fixture checks
|
|
83
|
+
|
|
84
|
+
Reward drafts may contain up to 50 named fixtures. JSON and numeric editor fields
|
|
85
|
+
remain strings while a draft is unfinished. `compileRewardAuthoring` is the shared
|
|
86
|
+
source/rubric compiler; `compileRewardFixtures` validates executable fixture input.
|
|
87
|
+
Published fixtures are an immutable evaluator-private `fixtureSetRef` asset included
|
|
88
|
+
in the Reward's `assets`, so editing the next release restores the same examples.
|
|
89
|
+
|
|
90
|
+
`queue_reward_check` takes an exact current Reward draft reference, timeout and
|
|
91
|
+
explicit spend ceiling. It stores a `reward_check` resource without publishing a
|
|
92
|
+
Reward, Task format, source or task evidence. The job binds the compiled Reward and
|
|
93
|
+
fixture hashes. Its worker resolves historical draft bytes even if another editor
|
|
94
|
+
saves or publishes a newer revision. Retry uses the same operation receipt; a
|
|
95
|
+
different request under that operation ID conflicts.
|
|
96
|
+
|
|
97
|
+
Hosts run `createRewardCheckWorker` with an execution adapter that records its
|
|
98
|
+
runtime/package identity and settles only after cleanup. The isolated adapter runs
|
|
99
|
+
portable deterministic checks and authored JavaScript with the supplied interpreter.
|
|
100
|
+
Human review remains pending; missing judge/learned-model adapters remain unavailable.
|
|
101
|
+
No fixture result implicitly calibrates a judge or qualifies a training runtime.
|
|
102
|
+
Per-fixture results distinguish a scored rejection, unavailable grading and grader
|
|
103
|
+
failure, and record whether each outcome matched its authored expectation.
|
|
104
|
+
|
|
105
|
+
Checks are indexed by Reward ID, retain their original draft reference and remain
|
|
106
|
+
readable after publication. Editing source or fixtures must mark prior checks as
|
|
107
|
+
historical. `cancel_reward_check` requests cancellation with revision concurrency;
|
|
108
|
+
the worker publishes terminal cancellation only after execution-owner cleanup.
|
|
109
|
+
|
|
110
|
+
### Source and execution ownership
|
|
111
|
+
|
|
82
112
|
Authored verifier code and rubrics use immutable `asset` resources. Publish source
|
|
83
113
|
and its Reward with `publish_resources`; the service checks UTF-8 size, SHA-256,
|
|
84
114
|
full reference identity, scope and evaluator visibility in the same transaction.
|
|
@@ -38,7 +38,7 @@ export async function finalizeAuthoringDraft(tx, input, published, now) {
|
|
|
38
38
|
await tx.put("draft", completed, draft.revision, { parentId: draft.targetKind, status: completed.status });
|
|
39
39
|
return { kind: "draft", id: completed.id, revision: completed.revision };
|
|
40
40
|
}
|
|
41
|
-
async function currentDraft(tx, ref) {
|
|
41
|
+
export async function currentDraft(tx, ref) {
|
|
42
42
|
const draft = await requireLearningRelease(tx, "draft", ref);
|
|
43
43
|
const current = await tx.get("draft", ref.id);
|
|
44
44
|
if (!current || !sameLearningRef(learningRef(current), ref))
|
|
@@ -3,6 +3,14 @@ import { ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema } from "@ope
|
|
|
3
3
|
import { RewardBindingSourceSchema, RewardReleaseRefSchema } from "../rewards.js";
|
|
4
4
|
import { LearningRevisionRefSchema } from "./contracts.js";
|
|
5
5
|
/** Strings intentionally preserve incomplete JSON/code until explicit publication. */
|
|
6
|
+
export const RewardFixtureAuthoringFieldsSchema = z.object({
|
|
7
|
+
id: ReleaseIdSchema, name: z.string().max(500),
|
|
8
|
+
input: z.string(), output: z.string(), expectedOutput: z.string(), evaluatorContext: z.string(),
|
|
9
|
+
artifactRefs: z.array(z.string().max(500)).max(100), runtimeEventRefs: z.array(z.string().max(500)).max(100),
|
|
10
|
+
infrastructureError: z.string().max(20_000),
|
|
11
|
+
expectedStatus: z.enum(["scored", "pending", "unavailable", "failed"]),
|
|
12
|
+
minimumScore: z.string(), maximumScore: z.string(), expectedPassed: z.enum(["true", "false", "any"]),
|
|
13
|
+
}).strict();
|
|
6
14
|
export const RewardAuthoringFieldsSchema = z.object({
|
|
7
15
|
name: z.string().max(500), description: z.string().max(10_000),
|
|
8
16
|
kind: z.enum(["custom_verifier", "state", "content", "schema", "artifact", "runtime_event", "model_judge", "learned_model", "human"]),
|
|
@@ -10,6 +18,7 @@ export const RewardAuthoringFieldsSchema = z.object({
|
|
|
10
18
|
schema: z.string(), reference: z.string(), events: z.string(), code: z.string(), exportName: z.string(), timeout: z.string(),
|
|
11
19
|
rubric: z.string(), providerId: z.string(), modelId: z.string(), modelRevision: z.string(), temperature: z.string(),
|
|
12
20
|
reviewerRole: z.string(), learnedId: z.string(), learnedHash: z.string(), inputContract: z.string(), minimum: z.string(), maximum: z.string(),
|
|
21
|
+
fixtures: z.array(RewardFixtureAuthoringFieldsSchema).max(50).optional(),
|
|
13
22
|
}).strict();
|
|
14
23
|
export const TaskFormatAuthoringFieldsSchema = z.object({
|
|
15
24
|
name: z.string().max(500), description: z.string().max(10_000), instructions: z.string().max(20_000),
|
|
@@ -46,6 +46,15 @@ export const TaskSourceMappingSchema = z.object({
|
|
|
46
46
|
familyKey: LearningJsonPointerSchema,
|
|
47
47
|
split: TaskSplitSchema,
|
|
48
48
|
}).strict();
|
|
49
|
+
/** An explicit Model edit starts new evidence; the original admissions remain
|
|
50
|
+
* in the exact parent package and are never approvals for this source. */
|
|
51
|
+
export const LearningReviewOriginSchema = z.object({
|
|
52
|
+
modelId: ReleaseIdSchema,
|
|
53
|
+
packageHash: ReleaseHashSchema,
|
|
54
|
+
taskset: LearningRevisionRefSchema,
|
|
55
|
+
batch: LearningRevisionRefSchema,
|
|
56
|
+
rewardBinding: LearningRevisionRefSchema,
|
|
57
|
+
}).strict();
|
|
49
58
|
export const LearningSourceContentSchema = z.object({
|
|
50
59
|
schemaVersion: z.literal("openpond.learningSource.v1"),
|
|
51
60
|
id: ReleaseIdSchema,
|
|
@@ -57,6 +66,7 @@ export const LearningSourceContentSchema = z.object({
|
|
|
57
66
|
allowedSplits: z.array(TaskSplitSchema).min(1).max(4),
|
|
58
67
|
mapping: TaskSourceMappingSchema.nullable(),
|
|
59
68
|
adapterVersion: z.string().trim().min(1).max(200).nullable(),
|
|
69
|
+
reviewOrigin: LearningReviewOriginSchema.optional(),
|
|
60
70
|
}).strict().superRefine((source, context) => {
|
|
61
71
|
if (source.kind !== "direct" && !source.mapping)
|
|
62
72
|
context.addIssue({ code: "custom", path: ["mapping"], message: "Mapped sources require an explicit mapping." });
|
package/dist/learning/index.js
CHANGED
|
@@ -8,3 +8,7 @@ export * from "./grade-worker.js";
|
|
|
8
8
|
export * from "./transport.js";
|
|
9
9
|
export * from "./errors.js";
|
|
10
10
|
export * from "./authoring.js";
|
|
11
|
+
export * from "./reward-authoring.js";
|
|
12
|
+
export * from "./reward-checks.js";
|
|
13
|
+
export * from "./reward-check-worker.js";
|
|
14
|
+
export * from "./reward-fixture-executor.js";
|
|
@@ -34,4 +34,6 @@ export const SealTaskBatchCommandSchema = command.extend({ action: z.literal("se
|
|
|
34
34
|
export const CancelTaskGradeCommandSchema = command.extend({ action: z.literal("cancel_grade"), gradeId: ReleaseIdSchema, expectedRevision: z.number().int().positive() }).strict();
|
|
35
35
|
export const SaveAuthoringDraftCommandSchema = command.extend({ action: z.literal("save_draft"), expectedRevision: z.number().int().nonnegative(), draft: AuthoringDraftInputSchema }).strict();
|
|
36
36
|
export const ArchiveAuthoringDraftCommandSchema = command.extend({ action: z.literal("archive_draft"), draft: LearningRevisionRefSchema }).strict();
|
|
37
|
-
export const
|
|
37
|
+
export const QueueRewardCheckCommandSchema = command.extend({ action: z.literal("queue_reward_check"), draft: LearningRevisionRefSchema, timeoutMs: z.number().int().min(100).max(300_000).default(30_000), maximumSpendUsd: z.number().nonnegative().max(1_000).default(0) }).strict();
|
|
38
|
+
export const CancelRewardCheckCommandSchema = command.extend({ action: z.literal("cancel_reward_check"), checkId: ReleaseIdSchema, expectedRevision: z.number().int().positive() }).strict();
|
|
39
|
+
export const LearningCommandSchema = z.union([QueueRewardCheckCommandSchema, CancelRewardCheckCommandSchema, SaveAuthoringDraftCommandSchema, ArchiveAuthoringDraftCommandSchema, PublishLearningResourceCommandSchema, PublishLearningResourcesCommandSchema, SubmitTaskExampleCommandSchema, SubmitTaskFeedbackCommandSchema, ApplyTaskCorrectionCommandSchema, ResolveTaskFeedbackCommandSchema, QueueTaskGradeCommandSchema, ReviewTaskEvidenceCommandSchema, SealTaskBatchCommandSchema, CancelTaskGradeCommandSchema]);
|
|
@@ -6,8 +6,10 @@ import { TasksetReleaseSchema } from "../tasksets.js";
|
|
|
6
6
|
import { LearningDomainError } from "./errors.js";
|
|
7
7
|
import { AuthoringDraftSchema } from "./authoring.js";
|
|
8
8
|
import { LearningTextAssetSchema } from "./assets.js";
|
|
9
|
+
import { RewardCheckRunSchema } from "./reward-checks.js";
|
|
9
10
|
export const learningResourceSchemas = {
|
|
10
11
|
draft: AuthoringDraftSchema,
|
|
12
|
+
reward_check: RewardCheckRunSchema,
|
|
11
13
|
asset: LearningTextAssetSchema,
|
|
12
14
|
definition: TaskDefinitionSchema, reward: RewardReleaseSchema, binding: RewardBindingSchema,
|
|
13
15
|
source: LearningSourceSchema, evidence: TaskEvidenceSchema, feedback: TaskFeedbackSchema,
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { RewardReleaseSchema, createRewardRelease } from "../rewards.js";
|
|
2
|
+
import { assertBoundedTaskJson } from "../task-schema.js";
|
|
3
|
+
import { RewardAuthoringFieldsSchema, RewardFixtureAuthoringFieldsSchema } from "./authoring.js";
|
|
4
|
+
import { createLearningTextAsset, verifyLearningTextAsset } from "./assets.js";
|
|
5
|
+
import { LearningJsonObjectSchema } from "./contracts.js";
|
|
6
|
+
import { LearningDomainError } from "./errors.js";
|
|
7
|
+
export const DEFAULT_REWARD_VERIFIER_SOURCE = `export function verify({ output, expectedOutput }) {
|
|
8
|
+
if (!expectedOutput || !Object.hasOwn(expectedOutput, "answer")) {
|
|
9
|
+
throw new Error("An expected answer is required.");
|
|
10
|
+
}
|
|
11
|
+
const passed = output.answer === expectedOutput.answer;
|
|
12
|
+
return { score: passed ? 1 : 0, passed, feedback: passed ? "Answer matched" : "Answer differed" };
|
|
13
|
+
}`;
|
|
14
|
+
/** Both editors and execution owners compile the same draft bytes. No publication occurs here. */
|
|
15
|
+
export function compileRewardAuthoring(input) {
|
|
16
|
+
assertBoundedTaskJson(input, 262_144);
|
|
17
|
+
const fields = RewardAuthoringFieldsSchema.parse(input.fields);
|
|
18
|
+
const base = input.base ? RewardReleaseSchema.parse(input.base) : null;
|
|
19
|
+
if (base && base.id !== input.id)
|
|
20
|
+
throw new LearningDomainError("reward_authoring_base_mismatch", 422);
|
|
21
|
+
const fixtureAsset = fields.fixtures?.length ? createLearningTextAsset({ text: JSON.stringify(fields.fixtures), path: "reward-fixtures.json", mediaType: "application/json", visibility: "verifier" }) : null;
|
|
22
|
+
let asset = null;
|
|
23
|
+
let implementation;
|
|
24
|
+
if (fields.kind === "custom_verifier") {
|
|
25
|
+
asset = createLearningTextAsset({ text: fields.code, path: "verifier.mjs", mediaType: "application/javascript", visibility: "verifier" });
|
|
26
|
+
implementation = { kind: fields.kind, verifierRef: asset.asset, exportName: fields.exportName, timeoutMs: authoringNumber(fields.timeout, "Time limit"), networkPolicy: "none" };
|
|
27
|
+
}
|
|
28
|
+
else if (fields.kind === "model_judge" || fields.kind === "human") {
|
|
29
|
+
if (!fields.rubric.trim())
|
|
30
|
+
throw new LearningDomainError("reward_rubric_required", 422, "Write the rubric before checking or publishing this Reward.");
|
|
31
|
+
asset = createLearningTextAsset({ text: fields.rubric, path: "rubric.md", mediaType: "text/markdown", visibility: "verifier" });
|
|
32
|
+
if (fields.kind === "human")
|
|
33
|
+
implementation = { kind: fields.kind, rubricRef: asset.asset, reviewerRole: fields.reviewerRole };
|
|
34
|
+
else {
|
|
35
|
+
const model = { providerId: fields.providerId, modelId: fields.modelId, revision: fields.modelRevision.trim() || null };
|
|
36
|
+
const temperature = authoringNumber(fields.temperature, "Temperature");
|
|
37
|
+
const previous = base?.implementation;
|
|
38
|
+
const unchanged = previous?.kind === "model_judge" && previous.rubricRef.contentHash === asset.asset.contentHash
|
|
39
|
+
&& previous.model?.providerId === model.providerId && previous.model?.modelId === model.modelId
|
|
40
|
+
&& previous.model?.revision === model.revision && (previous.temperature ?? 0) === temperature
|
|
41
|
+
&& base?.fixtureSetRef?.contentHash === fixtureAsset?.asset.contentHash;
|
|
42
|
+
implementation = { kind: fields.kind, rubricRef: asset.asset, model, temperature, calibrationStatus: unchanged ? previous.calibrationStatus : "pending" };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (fields.kind === "learned_model") {
|
|
46
|
+
parseRewardAuthoringObject(fields.inputContract, "Model input contract");
|
|
47
|
+
asset = createLearningTextAsset({ text: fields.inputContract, path: "input-contract.json", mediaType: "application/json", visibility: "verifier" });
|
|
48
|
+
implementation = { kind: fields.kind, modelVersion: { id: fields.learnedId, contentHash: fields.learnedHash }, inputContract: asset.asset };
|
|
49
|
+
}
|
|
50
|
+
else if (fields.kind === "state")
|
|
51
|
+
implementation = { kind: fields.kind, config: { fields: split(fields.fields) } };
|
|
52
|
+
else if (fields.kind === "content")
|
|
53
|
+
implementation = { kind: fields.kind, config: { outputField: fields.outputField, expectedField: fields.expectedField, ...(fields.expectedValue ? { expectedValue: fields.expectedValue } : {}) } };
|
|
54
|
+
else if (fields.kind === "schema")
|
|
55
|
+
implementation = { kind: fields.kind, config: { jsonSchema: parseRewardAuthoringObject(fields.schema, "Output schema") } };
|
|
56
|
+
else if (fields.kind === "artifact")
|
|
57
|
+
implementation = { kind: fields.kind, config: { refIncludes: fields.reference } };
|
|
58
|
+
else
|
|
59
|
+
implementation = { kind: fields.kind, config: { requiredEvents: split(fields.events) } };
|
|
60
|
+
const assets = [...(asset ? [asset] : []), ...(fixtureAsset ? [fixtureAsset] : [])];
|
|
61
|
+
const reward = createRewardRelease({
|
|
62
|
+
schemaVersion: "openpond.rewardRelease.v1", id: input.id, revision: (base?.revision ?? 0) + 1,
|
|
63
|
+
name: fields.name, description: fields.description, implementation,
|
|
64
|
+
rawScore: fields.kind === "learned_model" ? { minimum: authoringNumber(fields.minimum, "Minimum score"), maximum: authoringNumber(fields.maximum, "Maximum score") } : { minimum: 0, maximum: 1 },
|
|
65
|
+
assets: assets.map(value => value.asset), ...(fixtureAsset ? { fixtureSetRef: fixtureAsset.asset } : {}),
|
|
66
|
+
});
|
|
67
|
+
return { reward, assets };
|
|
68
|
+
}
|
|
69
|
+
export function rewardAuthoringFields(reward, sourceAsset, fixtureAsset = null) {
|
|
70
|
+
const implementation = reward?.implementation;
|
|
71
|
+
const ref = implementation && "verifierRef" in implementation ? implementation.verifierRef
|
|
72
|
+
: implementation && "rubricRef" in implementation ? implementation.rubricRef
|
|
73
|
+
: implementation && "inputContract" in implementation ? implementation.inputContract : null;
|
|
74
|
+
if (ref && !sourceAsset)
|
|
75
|
+
throw new LearningDomainError("reward_source_required", 422);
|
|
76
|
+
const source = ref && sourceAsset ? verifyLearningTextAsset(sourceAsset, ref) : "";
|
|
77
|
+
if (reward?.fixtureSetRef && !fixtureAsset)
|
|
78
|
+
throw new LearningDomainError("reward_fixtures_required", 422);
|
|
79
|
+
const fixtures = reward?.fixtureSetRef && fixtureAsset ? RewardFixtureAuthoringFieldsSchema.array().max(50).parse(JSON.parse(verifyLearningTextAsset(fixtureAsset, reward.fixtureSetRef))) : [];
|
|
80
|
+
const config = implementation && "config" in implementation ? implementation.config : {};
|
|
81
|
+
return {
|
|
82
|
+
name: reward?.name ?? "", description: reward?.description ?? "", kind: implementation?.kind ?? "state",
|
|
83
|
+
fields: strings(config.fields).join(", ") || "answer", outputField: text(config.outputField) || "text", expectedField: text(config.expectedField) || "text", expectedValue: text(config.expectedValue),
|
|
84
|
+
schema: JSON.stringify(config.jsonSchema ?? { type: "object", properties: { answer: { type: "string" } }, required: ["answer"] }, null, 2),
|
|
85
|
+
reference: text(config.refIncludes), events: strings(config.requiredEvents).join(", "),
|
|
86
|
+
code: implementation?.kind === "custom_verifier" ? source : DEFAULT_REWARD_VERIFIER_SOURCE,
|
|
87
|
+
exportName: implementation?.kind === "custom_verifier" ? implementation.exportName ?? "verify" : "verify",
|
|
88
|
+
timeout: String(implementation?.kind === "custom_verifier" ? implementation.timeoutMs : 5_000),
|
|
89
|
+
rubric: implementation?.kind === "model_judge" || implementation?.kind === "human" ? source : "",
|
|
90
|
+
providerId: implementation?.kind === "model_judge" ? implementation.model?.providerId ?? "" : "",
|
|
91
|
+
modelId: implementation?.kind === "model_judge" ? implementation.model?.modelId ?? "" : "",
|
|
92
|
+
modelRevision: implementation?.kind === "model_judge" ? implementation.model?.revision ?? "" : "",
|
|
93
|
+
temperature: String(implementation?.kind === "model_judge" ? implementation.temperature ?? 0 : 0),
|
|
94
|
+
reviewerRole: implementation?.kind === "human" ? implementation.reviewerRole : "Subject matter reviewer",
|
|
95
|
+
learnedId: implementation?.kind === "learned_model" ? implementation.modelVersion.id : "",
|
|
96
|
+
learnedHash: implementation?.kind === "learned_model" ? implementation.modelVersion.contentHash : "",
|
|
97
|
+
inputContract: implementation?.kind === "learned_model" ? source : "{}",
|
|
98
|
+
minimum: String(reward?.rawScore.minimum ?? 0), maximum: String(reward?.rawScore.maximum ?? 1),
|
|
99
|
+
...(fixtures.length ? { fixtures } : {}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function parseRewardAuthoringObject(value, label) {
|
|
103
|
+
try {
|
|
104
|
+
const parsed = JSON.parse(value);
|
|
105
|
+
assertBoundedTaskJson(parsed, 131_072);
|
|
106
|
+
return LearningJsonObjectSchema.parse(parsed);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
throw new LearningDomainError("reward_authoring_json_invalid", 422, `${label} must be a JSON object.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export function authoringNumber(value, label) {
|
|
113
|
+
const number = Number(value);
|
|
114
|
+
if (!value.trim() || !Number.isFinite(number))
|
|
115
|
+
throw new LearningDomainError("reward_authoring_number_invalid", 422, `${label} must be a finite number.`);
|
|
116
|
+
return number;
|
|
117
|
+
}
|
|
118
|
+
function text(value) { return typeof value === "string" ? value : ""; }
|
|
119
|
+
function strings(value) { return Array.isArray(value) ? value.filter((item) => typeof item === "string") : []; }
|
|
120
|
+
function split(value) { return value.split(",").map(part => part.trim()).filter(Boolean); }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LearningDomainError } from "./errors.js";
|
|
2
|
+
import { currentDraft } from "./authoring-service.js";
|
|
3
|
+
import { learningRef } from "./contracts.js";
|
|
4
|
+
import { compileRewardCheck, RewardCheckRunSchema } from "./reward-checks.js";
|
|
5
|
+
import { LearningConflictError, requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
6
|
+
export async function queueRewardCheck(tx, input, operationId, now) {
|
|
7
|
+
const draft = await currentDraft(tx, input.draft);
|
|
8
|
+
if (draft.targetKind !== "reward")
|
|
9
|
+
throw new LearningDomainError("reward_check_draft_kind_invalid", 422);
|
|
10
|
+
const base = draft.baseRelease ? await requireLearningRelease(tx, "reward", draft.baseRelease) : null;
|
|
11
|
+
const compiled = compileRewardCheck(draft, base);
|
|
12
|
+
const check = RewardCheckRunSchema.parse({
|
|
13
|
+
schemaVersion: "openpond.rewardCheckRun.v1", id: `reward-check-${operationId}`, revision: 1,
|
|
14
|
+
draft: learningRef(draft), reward: learningRef(compiled.reward), snapshotHash: compiled.snapshotHash,
|
|
15
|
+
fixtureRefs: compiled.fixtureRefs, status: "queued", runtime: null, results: [], matchesExpectations: null,
|
|
16
|
+
timeoutMs: input.timeoutMs, maximumSpendUsd: input.maximumSpendUsd,
|
|
17
|
+
leaseOwner: null, leaseExpiresAt: null, attemptCount: 0, failure: null, createdAt: now, updatedAt: now,
|
|
18
|
+
});
|
|
19
|
+
await tx.put("reward_check", check, 0, { parentId: draft.targetId, status: check.status });
|
|
20
|
+
return { kind: "reward_check", id: check.id, revision: check.revision };
|
|
21
|
+
}
|
|
22
|
+
export async function cancelRewardCheck(tx, input, now) {
|
|
23
|
+
const check = await requireLearningResource(tx, "reward_check", input.checkId);
|
|
24
|
+
if (check.revision !== input.expectedRevision)
|
|
25
|
+
throw new LearningConflictError("reward_check", check.id, input.expectedRevision, check.revision);
|
|
26
|
+
if (["completed", "failed", "cancelled"].includes(check.status))
|
|
27
|
+
return { kind: "reward_check", id: check.id, revision: check.revision };
|
|
28
|
+
const updated = RewardCheckRunSchema.parse({ ...check, revision: check.revision + 1, status: check.status === "queued" ? "cancelled" : "cancelling", updatedAt: now });
|
|
29
|
+
await tx.put("reward_check", updated, check.revision, { parentId: check.reward.id, status: updated.status });
|
|
30
|
+
return { kind: "reward_check", id: updated.id, revision: updated.revision };
|
|
31
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { contentHash } from "@openpond/harness";
|
|
2
|
+
import { BoundRewardResultSchema } from "../rewards.js";
|
|
3
|
+
import { sameLearningRef, learningRef } from "./contracts.js";
|
|
4
|
+
import { compileRewardCheck, matchRewardFixture, RewardCheckRunSchema, RewardCheckRuntimeSchema } from "./reward-checks.js";
|
|
5
|
+
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
6
|
+
export function createRewardCheckWorker(repository, executor, options) {
|
|
7
|
+
const runtime = RewardCheckRuntimeSchema.parse(executor.runtime);
|
|
8
|
+
const now = options.now ?? (() => new Date().toISOString());
|
|
9
|
+
const active = new Map();
|
|
10
|
+
const key = (scope, id) => JSON.stringify([scope, id]);
|
|
11
|
+
const terminal = (run) => ["completed", "failed", "cancelled"].includes(run.status);
|
|
12
|
+
async function run(scope, checkId) {
|
|
13
|
+
const claim = await repository.transaction(scope, async (tx) => {
|
|
14
|
+
const current = await requireLearningResource(tx, "reward_check", checkId);
|
|
15
|
+
if (terminal(current) || (current.leaseExpiresAt && Date.parse(current.leaseExpiresAt) > Date.parse(now())))
|
|
16
|
+
return { acquired: false, run: current };
|
|
17
|
+
const claimed = RewardCheckRunSchema.parse({ ...current, revision: current.revision + 1,
|
|
18
|
+
status: current.status === "cancelling" ? "cancelling" : "running", runtime: current.status === "cancelling" ? current.runtime : runtime,
|
|
19
|
+
leaseOwner: options.workerId, leaseExpiresAt: new Date(Date.parse(now()) + current.timeoutMs + 30_000).toISOString(),
|
|
20
|
+
attemptCount: current.attemptCount + 1, results: current.status === "cancelling" ? current.results : [], matchesExpectations: null, failure: null, updatedAt: now(),
|
|
21
|
+
});
|
|
22
|
+
await tx.put("reward_check", claimed, current.revision, { parentId: claimed.reward.id, status: claimed.status });
|
|
23
|
+
return { acquired: true, run: claimed };
|
|
24
|
+
});
|
|
25
|
+
if (!claim.acquired)
|
|
26
|
+
return claim.run;
|
|
27
|
+
if (claim.run.status === "cancelling") {
|
|
28
|
+
const cleaned = await executor.cancel({ scope, run: claim.run });
|
|
29
|
+
return finish(scope, claim.run, cleaned ? "cancelled" : "cancelling", null);
|
|
30
|
+
}
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
active.set(key(scope, checkId), controller);
|
|
33
|
+
const timer = setTimeout(() => controller.abort(new Error("reward_check_timeout")), claim.run.timeoutMs);
|
|
34
|
+
try {
|
|
35
|
+
const compiled = await repository.transaction(scope, async (tx) => {
|
|
36
|
+
const draft = await requireLearningRelease(tx, "draft", claim.run.draft);
|
|
37
|
+
if (draft.targetKind !== "reward")
|
|
38
|
+
throw new Error("reward_check_draft_kind_invalid");
|
|
39
|
+
const base = draft.baseRelease ? await requireLearningRelease(tx, "reward", draft.baseRelease) : null;
|
|
40
|
+
const compiled = compileRewardCheck(draft, base);
|
|
41
|
+
if (compiled.snapshotHash !== claim.run.snapshotHash || !sameLearningRef(learningRef(compiled.reward), claim.run.reward) || contentHash(compiled.fixtureRefs) !== contentHash(claim.run.fixtureRefs))
|
|
42
|
+
throw new Error("reward_check_snapshot_mismatch");
|
|
43
|
+
return compiled;
|
|
44
|
+
});
|
|
45
|
+
for (const fixture of compiled.fixtures) {
|
|
46
|
+
controller.signal.throwIfAborted();
|
|
47
|
+
const result = BoundRewardResultSchema.parse(await executor.execute({ ...compiled, scope, run: claim.run, fixture, signal: controller.signal }));
|
|
48
|
+
controller.signal.throwIfAborted();
|
|
49
|
+
if (result.graderId !== compiled.reward.id || !sameLearningRef(result.reward, claim.run.reward) || result.role !== "evaluation")
|
|
50
|
+
throw new Error("reward_check_result_identity_mismatch");
|
|
51
|
+
const retained = await repository.transaction(scope, async (tx) => {
|
|
52
|
+
const current = await requireLearningResource(tx, "reward_check", checkId);
|
|
53
|
+
if (!owns(current, claim.run) || terminal(current))
|
|
54
|
+
return current;
|
|
55
|
+
const updated = RewardCheckRunSchema.parse({ ...current, revision: current.revision + 1, results: [...current.results, matchRewardFixture(fixture, result)], updatedAt: now() });
|
|
56
|
+
await tx.put("reward_check", updated, current.revision, { parentId: current.reward.id, status: current.status });
|
|
57
|
+
return updated;
|
|
58
|
+
});
|
|
59
|
+
if (!owns(retained, claim.run) || terminal(retained))
|
|
60
|
+
return retained;
|
|
61
|
+
if (retained.status === "cancelling")
|
|
62
|
+
controller.abort(new Error("reward_check_cancel_requested"));
|
|
63
|
+
}
|
|
64
|
+
controller.signal.throwIfAborted();
|
|
65
|
+
return await finish(scope, claim.run, "completed", null);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (controller.signal.aborted) {
|
|
69
|
+
const cleaned = await executor.cancel({ scope, run: claim.run });
|
|
70
|
+
if (!cleaned)
|
|
71
|
+
return finish(scope, claim.run, "cancelling", "Execution cleanup is awaiting owner confirmation.");
|
|
72
|
+
if (controller.signal.reason instanceof Error && controller.signal.reason.message === "reward_check_cancel_requested")
|
|
73
|
+
return finish(scope, claim.run, "cancelled", null);
|
|
74
|
+
}
|
|
75
|
+
return await finish(scope, claim.run, "failed", error instanceof Error ? error.message : "Reward checks failed.");
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
active.delete(key(scope, checkId));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function owns(current, claim) { return current.leaseOwner === options.workerId && current.attemptCount === claim.attemptCount; }
|
|
83
|
+
async function finish(scope, claim, status, failure) {
|
|
84
|
+
return repository.transaction(scope, async (tx) => {
|
|
85
|
+
const current = await requireLearningResource(tx, "reward_check", claim.id);
|
|
86
|
+
if (!owns(current, claim) || terminal(current))
|
|
87
|
+
return current;
|
|
88
|
+
if (status === "completed" && current.results.length !== current.fixtureRefs.length)
|
|
89
|
+
throw new Error("reward_check_results_incomplete");
|
|
90
|
+
const updated = RewardCheckRunSchema.parse({ ...current, revision: current.revision + 1, status, failure,
|
|
91
|
+
matchesExpectations: status === "completed" ? current.results.every(result => result.matchesExpectation) : null,
|
|
92
|
+
leaseOwner: null, leaseExpiresAt: status === "cancelling" ? new Date(Date.parse(now()) + 5_000).toISOString() : null, updatedAt: now(),
|
|
93
|
+
});
|
|
94
|
+
await tx.put("reward_check", updated, current.revision, { parentId: current.reward.id, status: updated.status });
|
|
95
|
+
return updated;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
run,
|
|
100
|
+
requestCancellation(scope, id) { active.get(key(scope, id))?.abort(new Error("reward_check_cancel_requested")); },
|
|
101
|
+
async drain(scope, limit = 20) {
|
|
102
|
+
const candidates = await repository.transaction(scope, async (tx) => {
|
|
103
|
+
const rows = [];
|
|
104
|
+
for (const status of ["queued", "running", "cancelling"])
|
|
105
|
+
rows.push(...(await tx.list("reward_check", { status, limit: Math.max(1, Math.min(100, limit)) })).items);
|
|
106
|
+
return rows;
|
|
107
|
+
});
|
|
108
|
+
const completed = [];
|
|
109
|
+
for (const candidate of candidates)
|
|
110
|
+
completed.push(await run(scope, candidate.id));
|
|
111
|
+
return completed;
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema, contentHash } from "@openpond/harness";
|
|
3
|
+
import { BoundRewardResultSchema, createRewardBinding, executeRewardBinding } from "../rewards.js";
|
|
4
|
+
import { TaskRecordSchema } from "../tasksets.js";
|
|
5
|
+
import { LearningJsonObjectSchema, LearningRevisionRefSchema, learningRef } from "./contracts.js";
|
|
6
|
+
import { authoringNumber, compileRewardAuthoring, parseRewardAuthoringObject } from "./reward-authoring.js";
|
|
7
|
+
import { LearningDomainError } from "./errors.js";
|
|
8
|
+
export const RewardFixtureSchema = z.object({
|
|
9
|
+
id: ReleaseIdSchema, name: z.string().trim().min(1).max(500),
|
|
10
|
+
input: LearningJsonObjectSchema, output: LearningJsonObjectSchema,
|
|
11
|
+
expectedOutput: LearningJsonObjectSchema.nullable(), evaluatorContext: LearningJsonObjectSchema.nullable(),
|
|
12
|
+
artifactRefs: z.array(ReleaseIdSchema).max(100), runtimeEventRefs: z.array(ReleaseIdSchema).max(100),
|
|
13
|
+
infrastructureError: z.string().max(20_000).nullable(),
|
|
14
|
+
expected: z.discriminatedUnion("status", [
|
|
15
|
+
z.object({ status: z.literal("scored"), minimum: z.number().finite(), maximum: z.number().finite(), passed: z.boolean().nullable() }).strict(),
|
|
16
|
+
z.object({ status: z.enum(["pending", "unavailable", "failed"]) }).strict(),
|
|
17
|
+
]),
|
|
18
|
+
}).strict().superRefine((fixture, context) => {
|
|
19
|
+
if (fixture.expected.status === "scored" && fixture.expected.minimum > fixture.expected.maximum)
|
|
20
|
+
context.addIssue({ code: "custom", path: ["expected"], message: "Expected score minimum must not exceed maximum." });
|
|
21
|
+
});
|
|
22
|
+
export const RewardCheckRuntimeSchema = z.object({ id: ReleaseIdSchema, packageVersion: z.string().min(1).max(100), engine: z.string().min(1).max(200) }).strict();
|
|
23
|
+
export const RewardFixtureCheckResultSchema = z.object({
|
|
24
|
+
fixture: z.object({ id: ReleaseIdSchema, contentHash: ReleaseHashSchema }).strict(),
|
|
25
|
+
result: BoundRewardResultSchema, matchesExpectation: z.boolean(),
|
|
26
|
+
}).strict();
|
|
27
|
+
export const RewardCheckRunSchema = z.object({
|
|
28
|
+
schemaVersion: z.literal("openpond.rewardCheckRun.v1"), id: ReleaseIdSchema, revision: z.number().int().positive(),
|
|
29
|
+
draft: LearningRevisionRefSchema, reward: LearningRevisionRefSchema, snapshotHash: ReleaseHashSchema,
|
|
30
|
+
fixtureRefs: z.array(z.object({ id: ReleaseIdSchema, contentHash: ReleaseHashSchema }).strict()).min(1).max(50),
|
|
31
|
+
status: z.enum(["queued", "running", "completed", "failed", "cancelling", "cancelled"]),
|
|
32
|
+
runtime: RewardCheckRuntimeSchema.nullable(), results: z.array(RewardFixtureCheckResultSchema).max(50),
|
|
33
|
+
matchesExpectations: z.boolean().nullable(), failure: z.string().max(20_000).nullable(),
|
|
34
|
+
timeoutMs: z.number().int().min(100).max(300_000), maximumSpendUsd: z.number().nonnegative().max(1_000),
|
|
35
|
+
leaseOwner: ReleaseIdSchema.nullable(), leaseExpiresAt: ReleaseTimestampSchema.nullable(), attemptCount: z.number().int().nonnegative(),
|
|
36
|
+
createdAt: ReleaseTimestampSchema, updatedAt: ReleaseTimestampSchema,
|
|
37
|
+
}).strict();
|
|
38
|
+
export function compileRewardFixtures(fields) {
|
|
39
|
+
if (!fields.length || fields.length > 50)
|
|
40
|
+
throw new LearningDomainError("reward_check_fixtures_required", 422, "Add between one and 50 fixtures before checking this Reward.");
|
|
41
|
+
if (new Set(fields.map(field => field.id)).size !== fields.length)
|
|
42
|
+
throw new LearningDomainError("reward_fixture_id_duplicate", 422);
|
|
43
|
+
return fields.map(field => RewardFixtureSchema.parse({
|
|
44
|
+
id: field.id, name: field.name,
|
|
45
|
+
input: parseRewardAuthoringObject(field.input, `${field.name}: input`), output: parseRewardAuthoringObject(field.output, `${field.name}: output`),
|
|
46
|
+
expectedOutput: field.expectedOutput.trim() ? parseRewardAuthoringObject(field.expectedOutput, `${field.name}: expected answer`) : null,
|
|
47
|
+
evaluatorContext: field.evaluatorContext.trim() ? parseRewardAuthoringObject(field.evaluatorContext, `${field.name}: evaluator context`) : null,
|
|
48
|
+
artifactRefs: field.artifactRefs.map(value => value.trim()).filter(Boolean), runtimeEventRefs: field.runtimeEventRefs.map(value => value.trim()).filter(Boolean), infrastructureError: field.infrastructureError || null,
|
|
49
|
+
expected: field.expectedStatus === "scored" ? { status: field.expectedStatus, minimum: authoringNumber(field.minimumScore, `${field.name}: minimum score`), maximum: authoringNumber(field.maximumScore, `${field.name}: maximum score`), passed: field.expectedPassed === "any" ? null : field.expectedPassed === "true" } : { status: field.expectedStatus },
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
export function compileRewardCheck(draft, base) {
|
|
53
|
+
const compiled = compileRewardAuthoring({ id: draft.targetId, fields: draft.fields, base });
|
|
54
|
+
const fixtures = compileRewardFixtures(draft.fields.fixtures ?? []);
|
|
55
|
+
const fixtureRefs = fixtures.map(fixture => ({ id: fixture.id, contentHash: contentHash(fixture) }));
|
|
56
|
+
return { ...compiled, fixtures, fixtureRefs, snapshotHash: contentHash({ reward: compiled.reward, fixtures }) };
|
|
57
|
+
}
|
|
58
|
+
/** Fixture data is authored test data, never an owner-recorded production attempt. */
|
|
59
|
+
export async function executeRewardFixture(input) {
|
|
60
|
+
const fixture = RewardFixtureSchema.parse(input.fixture);
|
|
61
|
+
const task = TaskRecordSchema.parse({
|
|
62
|
+
id: fixture.id, clusterKey: fixture.id, split: "validation", input: fixture.input,
|
|
63
|
+
expectedOutput: fixture.expectedOutput, privilegedContextRef: null,
|
|
64
|
+
});
|
|
65
|
+
const binding = createRewardBinding({
|
|
66
|
+
schemaVersion: "openpond.rewardBinding.v1", id: `fixture-binding-${contentHash(learningRef(input.reward))}`, revision: 1,
|
|
67
|
+
sources: [{ graderId: input.reward.id, reward: learningRef(input.reward), role: "evaluation", normalization: input.reward.rawScore.minimum === 0 && input.reward.rawScore.maximum === 1 ? { kind: "identity" } : { kind: "linear", minimum: input.reward.rawScore.minimum, maximum: input.reward.rawScore.maximum, direction: "higher" }, weight: 1, required: true, hardGate: false, privileged: true, fixtureRefs: [] }],
|
|
68
|
+
aggregation: "weighted_mean", unscorable: "exclude_optional_require_all_required",
|
|
69
|
+
}, [input.reward]);
|
|
70
|
+
const composition = await executeRewardBinding({ binding, rewards: [input.reward], task,
|
|
71
|
+
evidence: { output: fixture.output, artifactRefs: fixture.artifactRefs, runtimeEventRefs: fixture.runtimeEventRefs, infrastructureError: fixture.infrastructureError },
|
|
72
|
+
signal: input.signal, customVerifier: input.customVerifier, modelJudge: input.modelJudge,
|
|
73
|
+
});
|
|
74
|
+
return composition.results[0];
|
|
75
|
+
}
|
|
76
|
+
export function matchRewardFixture(fixture, result) {
|
|
77
|
+
const expected = fixture.expected;
|
|
78
|
+
const matchesExpectation = result.status === expected.status && (expected.status !== "scored"
|
|
79
|
+
|| (result.rawScore !== null && result.rawScore >= expected.minimum && result.rawScore <= expected.maximum && (expected.passed === null || expected.passed === result.passed)));
|
|
80
|
+
return RewardFixtureCheckResultSchema.parse({ fixture: { id: fixture.id, contentHash: contentHash(fixture) }, result, matchesExpectation });
|
|
81
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { verifyLearningTextAsset } from "./assets.js";
|
|
2
|
+
import { executeRewardFixture } from "./reward-checks.js";
|
|
3
|
+
/** The supplied interpreter must settle only after its worker/process exits. */
|
|
4
|
+
export function createIsolatedRewardFixtureExecutor(options) {
|
|
5
|
+
return {
|
|
6
|
+
runtime: options.runtime,
|
|
7
|
+
execute(input) {
|
|
8
|
+
return executeRewardFixture({
|
|
9
|
+
reward: input.reward, fixture: input.fixture, signal: input.signal,
|
|
10
|
+
customVerifier: async ({ grader, task, evidence }) => {
|
|
11
|
+
const asset = input.assets.find(asset => asset.id === grader.verifierRef.id);
|
|
12
|
+
if (!asset)
|
|
13
|
+
throw new Error("reward_check_source_missing");
|
|
14
|
+
const source = verifyLearningTextAsset(asset, grader.verifierRef);
|
|
15
|
+
const result = await options.executeJavaScript({
|
|
16
|
+
source, exportName: grader.exportName, signal: input.signal,
|
|
17
|
+
timeoutMs: Math.min(grader.timeoutMs, input.run.timeoutMs),
|
|
18
|
+
value: { task, attempt: evidence, input: task.input, output: evidence.output, expectedOutput: task.expectedOutput,
|
|
19
|
+
evaluatorContext: input.fixture.evaluatorContext, infrastructureError: evidence.infrastructureError ?? null },
|
|
20
|
+
});
|
|
21
|
+
return { score: result.score, passed: result.passed, rewardEligible: grader.rewardEligible, failureClass: null,
|
|
22
|
+
feedback: [result.feedback], visibleEvidenceRefs: [], privilegedEvidenceRefs: result.evidenceRefs };
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
// No remote allocation; executeJavaScript's settlement contract confirms cleanup.
|
|
27
|
+
async cancel() { return true; },
|
|
28
|
+
};
|
|
29
|
+
}
|
package/dist/learning/service.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { saveAuthoringDraft, archiveAuthoringDraft, finalizeAuthoringDraft } from "./authoring-service.js";
|
|
2
|
+
import { queueRewardCheck, cancelRewardCheck } from "./reward-check-service.js";
|
|
2
3
|
import { LearningDomainError } from "./errors.js";
|
|
3
4
|
import { contentHash } from "@openpond/harness";
|
|
4
5
|
import { createRewardBinding, createRewardRelease, resolveBoundRewards } from "../rewards.js";
|
|
@@ -28,6 +29,12 @@ export function createLearningService(repository, options = {}) {
|
|
|
28
29
|
}
|
|
29
30
|
let pointers;
|
|
30
31
|
switch (input.action) {
|
|
32
|
+
case "queue_reward_check":
|
|
33
|
+
pointers = [await queueRewardCheck(transaction, input, operationId, now())];
|
|
34
|
+
break;
|
|
35
|
+
case "cancel_reward_check":
|
|
36
|
+
pointers = [await cancelRewardCheck(transaction, input, now())];
|
|
37
|
+
break;
|
|
31
38
|
case "save_draft":
|
|
32
39
|
pointers = [await saveAuthoringDraft(transaction, input, now())];
|
|
33
40
|
break;
|
package/dist/rewards.js
CHANGED
|
@@ -21,7 +21,10 @@ export const RewardReleaseContentSchema = z.object({
|
|
|
21
21
|
implementation: RewardImplementationSchema,
|
|
22
22
|
rawScore: z.object({ minimum: z.number().finite(), maximum: z.number().finite() }).strict(),
|
|
23
23
|
assets: z.array(ImmutableAssetRefSchema).max(1_000),
|
|
24
|
+
fixtureSetRef: ImmutableAssetRefSchema.optional(),
|
|
24
25
|
}).strict().superRefine((reward, context) => {
|
|
26
|
+
if (reward.fixtureSetRef && (reward.fixtureSetRef.visibility !== "verifier" || !reward.assets.some(asset => contentHash(asset) === contentHash(reward.fixtureSetRef))))
|
|
27
|
+
context.addIssue({ code: "custom", path: ["fixtureSetRef"], message: "Reward fixtures must be included as a private verifier asset." });
|
|
25
28
|
if (reward.rawScore.minimum >= reward.rawScore.maximum)
|
|
26
29
|
context.addIssue({ code: "custom", path: ["rawScore"], message: "A raw score contract requires minimum < maximum." });
|
|
27
30
|
if (reward.implementation.kind !== "learned_model" && (reward.rawScore.minimum !== 0 || reward.rawScore.maximum !== 1))
|
|
@@ -306,6 +306,18 @@ export declare const TaskBatchPackageMetadataSchema: z.ZodObject<{
|
|
|
306
306
|
host_private: "host_private";
|
|
307
307
|
}>;
|
|
308
308
|
}, z.core.$strict>>;
|
|
309
|
+
fixtureSetRef: z.ZodOptional<z.ZodObject<{
|
|
310
|
+
id: z.ZodString;
|
|
311
|
+
path: z.ZodString;
|
|
312
|
+
contentHash: z.ZodString;
|
|
313
|
+
sizeBytes: z.ZodNumber;
|
|
314
|
+
mediaType: z.ZodString;
|
|
315
|
+
visibility: z.ZodEnum<{
|
|
316
|
+
policy: "policy";
|
|
317
|
+
verifier: "verifier";
|
|
318
|
+
host_private: "host_private";
|
|
319
|
+
}>;
|
|
320
|
+
}, z.core.$strict>>;
|
|
309
321
|
contentHash: z.ZodString;
|
|
310
322
|
}, z.core.$strict>>;
|
|
311
323
|
admissions: z.ZodArray<z.ZodObject<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admission.d.ts","sourceRoot":"","sources":["../../../../../src/learning/admission.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"admission.d.ts","sourceRoot":"","sources":["../../../../../src/learning/admission.ts"],"names":[],"mappings":"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"}
|