@openpond/evals 0.12.3 → 0.12.5

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.
Files changed (53) hide show
  1. package/LEARNING.md +43 -0
  2. package/dist/javascript-isolate-process-entry.js +4 -1
  3. package/dist/javascript-isolate-process-source.js +1 -1
  4. package/dist/javascript-isolate-process.js +36 -2
  5. package/dist/javascript-isolate.js +8 -2
  6. package/dist/javascript-verifier-node.js +1 -0
  7. package/dist/javascript-verifier-worker-source.js +1 -1
  8. package/dist/learning/index.js +1 -0
  9. package/dist/learning/iteration-dispatch-commands.js +1 -1
  10. package/dist/learning/iteration-dispatch-contracts.js +27 -0
  11. package/dist/learning/iteration-dispatch-deferral.js +28 -0
  12. package/dist/learning/iteration-dispatch-worker.js +34 -5
  13. package/dist/tool-learning/actions.js +62 -0
  14. package/dist/tool-learning/consultation.js +198 -0
  15. package/dist/tool-learning/episodes.js +284 -0
  16. package/dist/tool-learning/index.js +6 -0
  17. package/dist/tool-learning/installations.js +151 -0
  18. package/dist/tool-learning/policy.js +38 -0
  19. package/dist/tool-learning/primitives.js +87 -0
  20. package/dist/types/javascript-isolate-process.d.ts +7 -0
  21. package/dist/types/javascript-isolate-process.d.ts.map +1 -1
  22. package/dist/types/javascript-isolate.d.ts +3 -1
  23. package/dist/types/javascript-isolate.d.ts.map +1 -1
  24. package/dist/types/javascript-verifier-node.d.ts +1 -0
  25. package/dist/types/javascript-verifier-node.d.ts.map +1 -1
  26. package/dist/types/learning/index.d.ts +1 -0
  27. package/dist/types/learning/index.d.ts.map +1 -1
  28. package/dist/types/learning/iteration-dispatch-contracts.d.ts +45 -0
  29. package/dist/types/learning/iteration-dispatch-contracts.d.ts.map +1 -1
  30. package/dist/types/learning/iteration-dispatch-deferral.d.ts +71 -0
  31. package/dist/types/learning/iteration-dispatch-deferral.d.ts.map +1 -0
  32. package/dist/types/learning/iteration-dispatch-worker.d.ts +7 -2
  33. package/dist/types/learning/iteration-dispatch-worker.d.ts.map +1 -1
  34. package/dist/types/learning/repository.d.ts +20 -0
  35. package/dist/types/learning/repository.d.ts.map +1 -1
  36. package/dist/types/learning/transport.d.ts +20 -0
  37. package/dist/types/learning/transport.d.ts.map +1 -1
  38. package/dist/types/tool-learning/actions.d.ts +54 -0
  39. package/dist/types/tool-learning/actions.d.ts.map +1 -0
  40. package/dist/types/tool-learning/consultation.d.ts +229 -0
  41. package/dist/types/tool-learning/consultation.d.ts.map +1 -0
  42. package/dist/types/tool-learning/episodes.d.ts +1058 -0
  43. package/dist/types/tool-learning/episodes.d.ts.map +1 -0
  44. package/dist/types/tool-learning/index.d.ts +7 -0
  45. package/dist/types/tool-learning/index.d.ts.map +1 -0
  46. package/dist/types/tool-learning/installations.d.ts +296 -0
  47. package/dist/types/tool-learning/installations.d.ts.map +1 -0
  48. package/dist/types/tool-learning/policy.d.ts +3 -0
  49. package/dist/types/tool-learning/policy.d.ts.map +1 -0
  50. package/dist/types/tool-learning/primitives.d.ts +73 -0
  51. package/dist/types/tool-learning/primitives.d.ts.map +1 -0
  52. package/package.json +5 -1
  53. package/schemas/learning/v1/dispatch.schema.json +100 -1
@@ -0,0 +1,284 @@
1
+ import { z } from "zod";
2
+ import { ToolLearningActionSchema } from "./actions.js";
3
+ import { TOOL_LEARNING_LIMITS, ToolLearningAssetSchema, ToolLearningEnvironmentSchema, ToolLearningHashSchema as Hash, ToolLearningIdSchema as Id, ToolLearningRefSchema as Ref, ToolLearningSanitizationSchema, ToolLearningTimestampSchema as Timestamp, boundedToolLearningSchema, toolLearningContentHash, toolLearningText, } from "./primitives.js";
4
+ export const ToolEpisodeAttemptSchema = z
5
+ .object({
6
+ intent: toolLearningText(2_000),
7
+ tool: z
8
+ .object({
9
+ name: z.string().min(1).max(200),
10
+ version: z.string().max(200).nullable(),
11
+ server: z.string().max(200).nullable(),
12
+ })
13
+ .strict(),
14
+ action: ToolLearningActionSchema,
15
+ actionHash: Hash,
16
+ environment: ToolLearningEnvironmentSchema,
17
+ contextAssets: z.array(ToolLearningAssetSchema).max(TOOL_LEARNING_LIMITS.assetsPerEpisode),
18
+ selection: z.discriminatedUnion("kind", [
19
+ z.object({ kind: z.literal("eligible_attempt") }).strict(),
20
+ z
21
+ .object({
22
+ kind: z.literal("unchanged_control"),
23
+ numerator: z.number().int().positive(),
24
+ denominator: z.number().int().positive(),
25
+ policyHash: Hash,
26
+ })
27
+ .strict(),
28
+ ]),
29
+ })
30
+ .strict()
31
+ .superRefine((attempt, context) => {
32
+ if (toolLearningContentHash(attempt.action) !== attempt.actionHash)
33
+ context.addIssue({
34
+ code: "custom",
35
+ path: ["actionHash"],
36
+ message: "Action bytes differ from their hash.",
37
+ });
38
+ if (attempt.selection.kind === "unchanged_control" &&
39
+ attempt.selection.numerator > attempt.selection.denominator)
40
+ context.addIssue({
41
+ code: "custom",
42
+ path: ["selection"],
43
+ message: "Sampling probability cannot exceed one.",
44
+ });
45
+ });
46
+ export const ToolEpisodeFailureKindSchema = z.enum([
47
+ "validation_failure",
48
+ "execution_failure",
49
+ "process_failure",
50
+ "timeout",
51
+ "cancelled",
52
+ "infrastructure_failure",
53
+ "authorization_denied",
54
+ "outcome_failure",
55
+ "unknown_failure",
56
+ ]);
57
+ const ObservationBase = {
58
+ attempt: Ref,
59
+ actionHash: Hash,
60
+ execution: z.enum(["not_executed", "executed", "unknown"]),
61
+ sideEffects: z.enum(["none", "possible", "observed", "unknown"]),
62
+ resultExcerpt: toolLearningText(TOOL_LEARNING_LIMITS.resultBytes),
63
+ resultHash: Hash.nullable(),
64
+ assets: z.array(ToolLearningAssetSchema).max(TOOL_LEARNING_LIMITS.assetsPerEpisode),
65
+ };
66
+ export const ToolEpisodeObservationSchema = z
67
+ .discriminatedUnion("outcome", [
68
+ z
69
+ .object({
70
+ ...ObservationBase,
71
+ outcome: z.literal("succeeded"),
72
+ exitCode: z.literal(0).nullable(),
73
+ })
74
+ .strict(),
75
+ z
76
+ .object({
77
+ ...ObservationBase,
78
+ outcome: z.literal("failed"),
79
+ classification: ToolEpisodeFailureKindSchema,
80
+ errorCode: z.string().min(1).max(200),
81
+ message: toolLearningText(2_000),
82
+ exitCode: z.number().int().min(-255).max(255).nullable(),
83
+ })
84
+ .strict(),
85
+ z
86
+ .object({
87
+ ...ObservationBase,
88
+ outcome: z.literal("incomplete"),
89
+ reason: z.enum([
90
+ "completion_not_observed",
91
+ "observer_restarted",
92
+ "transport_interrupted",
93
+ "coverage_gap",
94
+ ]),
95
+ })
96
+ .strict(),
97
+ ])
98
+ .superRefine((observation, context) => {
99
+ if (observation.execution === "not_executed" && observation.sideEffects !== "none")
100
+ context.addIssue({
101
+ code: "custom",
102
+ path: ["sideEffects"],
103
+ message: "An unexecuted action cannot claim tool effects.",
104
+ });
105
+ if (observation.outcome === "succeeded" && observation.execution !== "executed")
106
+ context.addIssue({
107
+ code: "custom",
108
+ path: ["execution"],
109
+ message: "Successful execution requires an observed execution.",
110
+ });
111
+ if (observation.outcome !== "failed")
112
+ return;
113
+ if (observation.classification === "validation_failure" &&
114
+ observation.execution !== "not_executed")
115
+ context.addIssue({
116
+ code: "custom",
117
+ path: ["execution"],
118
+ message: "Pre-execution validation failure must be unexecuted.",
119
+ });
120
+ if (observation.classification === "process_failure" &&
121
+ (observation.execution !== "executed" ||
122
+ observation.exitCode === null ||
123
+ observation.exitCode === 0))
124
+ context.addIssue({
125
+ code: "custom",
126
+ path: ["exitCode"],
127
+ message: "Process failure requires a nonzero observed exit.",
128
+ });
129
+ });
130
+ export const ToolEpisodeRecoveryLinkSchema = z
131
+ .object({
132
+ failedAttempt: Ref,
133
+ failedObservation: Ref,
134
+ replacementAttempt: Ref,
135
+ goalId: Id,
136
+ basis: z.enum(["explicit_relation", "artifact_lineage", "unverified"]),
137
+ attributionEvidence: z.array(Ref).max(16),
138
+ })
139
+ .strict()
140
+ .superRefine((link, context) => {
141
+ if (link.failedAttempt.id === link.replacementAttempt.id)
142
+ context.addIssue({
143
+ code: "custom",
144
+ message: "A recovery must reference a different attempt.",
145
+ });
146
+ if (link.basis !== "unverified" && link.attributionEvidence.length === 0)
147
+ context.addIssue({
148
+ code: "custom",
149
+ path: ["attributionEvidence"],
150
+ message: "Recovery attribution needs retained evidence.",
151
+ });
152
+ });
153
+ /** A producer supplies a claim/reference. Intake must resolve its authentic owner
154
+ * receipt; possession of an append credential never grants verifier authority. */
155
+ export const ToolEpisodeVerificationSchema = z
156
+ .object({
157
+ attempt: Ref,
158
+ actionHash: Hash,
159
+ outcome: z.enum(["passed", "failed", "unknown"]),
160
+ verifierRelease: Ref.nullable(),
161
+ verifierReceipt: Ref.nullable(),
162
+ environmentFingerprint: Hash,
163
+ resetStateHash: Hash.nullable(),
164
+ outputArtifacts: z.array(ToolLearningAssetSchema).max(TOOL_LEARNING_LIMITS.assetsPerEpisode),
165
+ reason: toolLearningText(2_000),
166
+ })
167
+ .strict()
168
+ .superRefine((verification, context) => {
169
+ if (verification.outcome !== "unknown" &&
170
+ (!verification.verifierRelease || !verification.verifierReceipt))
171
+ context.addIssue({
172
+ code: "custom",
173
+ message: "A verification outcome requires an exact verifier and execution receipt.",
174
+ });
175
+ });
176
+ const Event = z
177
+ .object({
178
+ schemaVersion: z.literal("openpond.toolEpisodeEvent.v1"),
179
+ operationId: Id,
180
+ installationId: Id,
181
+ episodeId: Id,
182
+ eventId: Id,
183
+ sessionId: Id,
184
+ parentSessionId: Id.nullable(),
185
+ turnId: Id.nullable(),
186
+ callId: Id,
187
+ occurredAt: Timestamp,
188
+ sequence: z.number().int().nonnegative(),
189
+ adapterVersion: z.string().min(1).max(200),
190
+ sanitization: ToolLearningSanitizationSchema,
191
+ contentHash: Hash,
192
+ })
193
+ .strict();
194
+ export const ToolEpisodeEventSchema = boundedToolLearningSchema(z
195
+ .discriminatedUnion("eventKind", [
196
+ Event.extend({ eventKind: z.literal("attempt"), payload: ToolEpisodeAttemptSchema }).strict(),
197
+ Event.extend({
198
+ eventKind: z.literal("observation"),
199
+ payload: ToolEpisodeObservationSchema,
200
+ }).strict(),
201
+ Event.extend({
202
+ eventKind: z.literal("recovery_link"),
203
+ payload: ToolEpisodeRecoveryLinkSchema,
204
+ }).strict(),
205
+ Event.extend({
206
+ eventKind: z.literal("verification"),
207
+ payload: ToolEpisodeVerificationSchema,
208
+ }).strict(),
209
+ Event.extend({
210
+ eventKind: z.literal("lineage"),
211
+ payload: z
212
+ .object({
213
+ relation: z.enum(["fork", "split", "reopen"]),
214
+ parentEpisode: Ref,
215
+ parentSessionId: Id,
216
+ reason: toolLearningText(1_000),
217
+ })
218
+ .strict(),
219
+ }).strict(),
220
+ ])
221
+ .superRefine((event, context) => {
222
+ const { contentHash, ...body } = event;
223
+ if (toolLearningContentHash(body) !== contentHash)
224
+ context.addIssue({
225
+ code: "custom",
226
+ path: ["contentHash"],
227
+ message: "Episode event content hash mismatch.",
228
+ });
229
+ }), TOOL_LEARNING_LIMITS.eventBytes);
230
+ export function sealToolEpisodeEvent(value) {
231
+ const hash = toolLearningContentHash(value);
232
+ if (!value ||
233
+ typeof value !== "object" ||
234
+ Array.isArray(value) ||
235
+ Object.hasOwn(value, "contentHash"))
236
+ throw new Error("tool_episode_unsigned_envelope_required");
237
+ return ToolEpisodeEventSchema.parse({ ...value, contentHash: hash });
238
+ }
239
+ export const ToolEpisodeAppendSchema = boundedToolLearningSchema(z
240
+ .object({
241
+ schemaVersion: z.literal("openpond.toolEpisodeAppend.v1"),
242
+ operationId: Id,
243
+ installationId: Id,
244
+ events: z.array(ToolEpisodeEventSchema).min(1).max(TOOL_LEARNING_LIMITS.eventsPerAppend),
245
+ })
246
+ .strict()
247
+ .superRefine((append, context) => {
248
+ if (append.events.some((event) => event.installationId !== append.installationId))
249
+ context.addIssue({
250
+ code: "custom",
251
+ path: ["events"],
252
+ message: "Append events must belong to the exact installation.",
253
+ });
254
+ if (new Set(append.events.map((event) => event.eventId)).size !== append.events.length)
255
+ context.addIssue({
256
+ code: "custom",
257
+ path: ["events"],
258
+ message: "Append event IDs must be unique.",
259
+ });
260
+ }), TOOL_LEARNING_LIMITS.eventBytes * TOOL_LEARNING_LIMITS.eventsPerAppend);
261
+ export const ToolEpisodeAppendReceiptSchema = z
262
+ .object({
263
+ schemaVersion: z.literal("openpond.toolEpisodeAppendReceipt.v1"),
264
+ operationId: Id,
265
+ requestHash: Hash,
266
+ installationId: Id,
267
+ teamId: Id,
268
+ projectId: Id,
269
+ receivedAt: Timestamp,
270
+ events: z
271
+ .array(z
272
+ .object({
273
+ eventId: Id,
274
+ contentHash: Hash,
275
+ state: z.enum(["retained", "already_retained", "privacy_rejected"]),
276
+ receiptId: Id,
277
+ reason: z.string().max(200).nullable(),
278
+ })
279
+ .strict())
280
+ .min(1)
281
+ .max(TOOL_LEARNING_LIMITS.eventsPerAppend),
282
+ learningEnrollment: z.literal(false),
283
+ })
284
+ .strict();
@@ -0,0 +1,6 @@
1
+ export * from "./primitives.js";
2
+ export * from "./actions.js";
3
+ export * from "./episodes.js";
4
+ export * from "./installations.js";
5
+ export * from "./consultation.js";
6
+ export * from "./policy.js";
@@ -0,0 +1,151 @@
1
+ import { z } from "zod";
2
+ import { TOOL_LEARNING_LIMITS, ToolLearningClientSchema, ToolLearningHashSchema as Hash, ToolLearningIdSchema as Id, ToolLearningRefSchema as Ref, ToolLearningScopeSchema, ToolLearningTimestampSchema as Timestamp, boundedToolLearningSchema, } from "./primitives.js";
3
+ export const ToolLearningCapturePolicySchema = z
4
+ .object({
5
+ revision: z.number().int().positive(),
6
+ permittedTools: z.array(z.string().min(1).max(200)).min(1).max(100),
7
+ workspaceRootHashes: z.array(Hash).min(1).max(32),
8
+ permittedFields: z
9
+ .array(z.enum(["action", "intent", "state", "result_excerpt", "artifact_reference"]))
10
+ .min(1)
11
+ .max(5),
12
+ unchangedControls: z
13
+ .object({
14
+ numerator: z.number().int().nonnegative(),
15
+ denominator: z.number().int().positive(),
16
+ })
17
+ .strict(),
18
+ maximumEventBytes: z.number().int().positive().max(TOOL_LEARNING_LIMITS.eventBytes),
19
+ maximumEpisodeBytes: z.number().int().positive().max(TOOL_LEARNING_LIMITS.episodeBytes),
20
+ maximumEpisodeEvents: z.number().int().positive().max(TOOL_LEARNING_LIMITS.eventsPerEpisode),
21
+ maximumQueueBytes: z.number().int().positive().max(TOOL_LEARNING_LIMITS.queueBytes),
22
+ maximumQueueEvents: z.number().int().positive().max(TOOL_LEARNING_LIMITS.queueEvents),
23
+ maximumQueueAgeSeconds: z.number().int().positive().max(TOOL_LEARNING_LIMITS.queueAgeSeconds),
24
+ rawRetentionDays: z.number().int().min(1).max(30),
25
+ purposes: z
26
+ .array(z.enum(["capture", "consultation"]))
27
+ .min(1)
28
+ .max(2),
29
+ modelUpdates: z.literal("requires_separate_review"),
30
+ variantGeneration: z.literal("disabled"),
31
+ })
32
+ .strict()
33
+ .superRefine((policy, context) => {
34
+ if (policy.unchangedControls.numerator > policy.unchangedControls.denominator)
35
+ context.addIssue({
36
+ code: "custom",
37
+ path: ["unchangedControls"],
38
+ message: "Sampling probability cannot exceed one.",
39
+ });
40
+ for (const key of [
41
+ "permittedTools",
42
+ "workspaceRootHashes",
43
+ "permittedFields",
44
+ "purposes",
45
+ ])
46
+ if (new Set(policy[key]).size !== policy[key].length)
47
+ context.addIssue({
48
+ code: "custom",
49
+ path: [key],
50
+ message: "Policy entries must be unique.",
51
+ });
52
+ if (policy.maximumEpisodeBytes < policy.maximumEventBytes ||
53
+ policy.maximumQueueBytes < policy.maximumEventBytes)
54
+ context.addIssue({
55
+ code: "custom",
56
+ message: "Episode and queue capacities must fit one permitted event.",
57
+ });
58
+ });
59
+ export const ToolLearningCoverageSchema = z
60
+ .object({
61
+ receipt: Ref.nullable(),
62
+ start: z.enum(["observed", "documented", "unsupported", "unqualified"]),
63
+ resume: z.enum(["observed", "documented", "unsupported", "unqualified"]),
64
+ compaction: z.enum(["observed", "documented", "unsupported", "unqualified"]),
65
+ executionFailure: z.enum(["observed", "documented", "unsupported", "unqualified"]),
66
+ processFailure: z.enum(["observed", "documented", "unsupported", "unqualified"]),
67
+ validationFailure: z.enum(["observed", "documented", "unsupported", "unqualified"]),
68
+ nestedCalls: z.enum(["observed", "documented", "unsupported", "unqualified"]),
69
+ contextRefresh: z.enum([
70
+ "session_start",
71
+ "start_resume",
72
+ "start_resume_compaction",
73
+ "revision_aware_turn",
74
+ "unqualified",
75
+ ]),
76
+ gaps: z.array(z.string().min(1).max(500)).max(32),
77
+ })
78
+ .strict()
79
+ .superRefine((coverage, context) => {
80
+ if (Object.values(coverage).includes("observed") && !coverage.receipt)
81
+ context.addIssue({
82
+ code: "custom",
83
+ path: ["receipt"],
84
+ message: "Observed coverage requires a qualification receipt.",
85
+ });
86
+ });
87
+ export const ToolLearningRegistrationSchema = boundedToolLearningSchema(z
88
+ .object({
89
+ schemaVersion: z.literal("openpond.toolLearningRegistration.v1"),
90
+ operationId: Id,
91
+ installationId: Id,
92
+ projectId: Id,
93
+ machineSourceId: Id,
94
+ client: ToolLearningClientSchema,
95
+ clientVersion: z.string().min(1).max(200),
96
+ adapterRelease: Ref,
97
+ collectionPolicy: ToolLearningCapturePolicySchema,
98
+ })
99
+ .strict(), TOOL_LEARNING_LIMITS.eventBytes);
100
+ /** Status deliberately exposes capability/expiry metadata, never the credential. */
101
+ export const ToolLearningInstallationSchema = z
102
+ .object({
103
+ schemaVersion: z.literal("openpond.toolLearningInstallation.v1"),
104
+ id: Id,
105
+ revision: z.number().int().positive(),
106
+ scope: ToolLearningScopeSchema,
107
+ ownerUserId: Id,
108
+ machineSourceId: Id,
109
+ client: ToolLearningClientSchema,
110
+ clientVersion: z.string().min(1).max(200),
111
+ adapterRelease: Ref,
112
+ state: z.enum(["pending_client_trust", "enabled", "disabled", "revoked"]),
113
+ collectionPolicy: ToolLearningCapturePolicySchema,
114
+ collectionPolicyHash: Hash,
115
+ coverage: ToolLearningCoverageSchema,
116
+ credential: z
117
+ .object({
118
+ id: Id,
119
+ expiresAt: Timestamp,
120
+ revokedAt: Timestamp.nullable(),
121
+ capabilities: z
122
+ .array(z.enum(["episode_append", "manifest_read", "consultation_submit", "consultation_read"]))
123
+ .min(1)
124
+ .max(4),
125
+ })
126
+ .strict()
127
+ .nullable(),
128
+ createdAt: Timestamp,
129
+ updatedAt: Timestamp,
130
+ })
131
+ .strict();
132
+ export const ToolLearningInstallationUpdateSchema = z
133
+ .object({
134
+ operationId: Id,
135
+ expectedRevision: z.number().int().positive(),
136
+ state: z.enum(["enabled", "disabled", "revoked"]),
137
+ })
138
+ .strict();
139
+ export const ToolEpisodeOriginSchema = z
140
+ .object({
141
+ schemaVersion: z.literal("openpond.toolEpisodeOrigin.v1"),
142
+ installationId: Id,
143
+ projectId: Id,
144
+ ownerUserId: Id,
145
+ episode: Ref,
146
+ event: Ref,
147
+ appendReceipt: Ref,
148
+ purpose: z.literal("private_dataset_evidence"),
149
+ trainingConsent: z.literal("not_granted"),
150
+ })
151
+ .strict();
@@ -0,0 +1,38 @@
1
+ import { ToolEpisodeEventSchema } from "./episodes.js";
2
+ import { ToolLearningCapturePolicySchema } from "./installations.js";
3
+ import { toolLearningContentHash } from "./primitives.js";
4
+ /** Shared local-persistence/intake boundary. A hash alone does not grant consent. */
5
+ export function assertToolEpisodeCapturePolicy(eventValue, policyValue) {
6
+ const event = ToolEpisodeEventSchema.parse(eventValue);
7
+ const policy = ToolLearningCapturePolicySchema.parse(policyValue);
8
+ if (!policy.purposes.includes("capture"))
9
+ throw new Error("tool_learning_capture_not_enabled");
10
+ if (event.sanitization.policyRevision !== policy.revision ||
11
+ event.sanitization.policyHash !== toolLearningContentHash(policy))
12
+ throw new Error("tool_learning_capture_policy_changed");
13
+ if (new TextEncoder().encode(JSON.stringify(event)).byteLength > policy.maximumEventBytes)
14
+ throw new Error("tool_learning_event_policy_limit");
15
+ const permits = (field) => policy.permittedFields.includes(field);
16
+ if (event.eventKind === "attempt") {
17
+ if (!policy.permittedTools.includes(event.payload.tool.name))
18
+ throw new Error("tool_learning_tool_outside_collection_policy");
19
+ if (!permits("action") ||
20
+ (!permits("intent") && event.payload.intent !== "") ||
21
+ (!permits("state") && Object.keys(event.payload.environment.state).length > 0) ||
22
+ (!permits("artifact_reference") && event.payload.contextAssets.length > 0))
23
+ throw new Error("tool_learning_attempt_field_outside_collection_policy");
24
+ }
25
+ if (event.eventKind === "observation") {
26
+ if ((!permits("result_excerpt") &&
27
+ (event.payload.resultExcerpt !== "" ||
28
+ (event.payload.outcome === "failed" && event.payload.message !== ""))) ||
29
+ (!permits("artifact_reference") && event.payload.assets.length > 0))
30
+ throw new Error("tool_learning_result_field_outside_collection_policy");
31
+ }
32
+ if (event.eventKind === "verification" &&
33
+ ((!permits("result_excerpt") && event.payload.reason !== "") ||
34
+ (!permits("artifact_reference") && event.payload.outputArtifacts.length > 0)))
35
+ throw new Error("tool_learning_verification_field_outside_collection_policy");
36
+ if (event.eventKind === "lineage" && !permits("intent") && event.payload.reason !== "")
37
+ throw new Error("tool_learning_lineage_field_outside_collection_policy");
38
+ }
@@ -0,0 +1,87 @@
1
+ import { z } from "zod";
2
+ import { contentHash, ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema, } from "@openpond/harness";
3
+ import { assertBoundedTaskJson } from "../task-schema-validation.js";
4
+ export const TOOL_LEARNING_LIMITS = Object.freeze({
5
+ eventBytes: 65_536,
6
+ actionBytes: 16_384,
7
+ resultBytes: 8_192,
8
+ stateBytes: 8_192,
9
+ eventsPerAppend: 32,
10
+ eventsPerEpisode: 256,
11
+ episodeBytes: 2_097_152,
12
+ assetBytes: 1_048_576,
13
+ assetsPerEpisode: 16,
14
+ queueBytes: 52_428_800,
15
+ queueEvents: 5_000,
16
+ queueAgeSeconds: 86_400,
17
+ capabilities: 32,
18
+ consultationRounds: 3,
19
+ consultationBytes: 65_536,
20
+ manifestSeconds: 300,
21
+ });
22
+ export const ToolLearningIdSchema = ReleaseIdSchema;
23
+ export const ToolLearningHashSchema = ReleaseHashSchema;
24
+ export const ToolLearningTimestampSchema = ReleaseTimestampSchema;
25
+ export const ToolLearningClientSchema = z.enum(["codex", "claude_code", "opencode", "openpond"]);
26
+ export const ToolLearningRefSchema = z
27
+ .object({ id: ReleaseIdSchema, contentHash: ReleaseHashSchema })
28
+ .strict();
29
+ export const ToolLearningScopeSchema = z
30
+ .object({ teamId: ReleaseIdSchema, projectId: ReleaseIdSchema })
31
+ .strict();
32
+ /** Run the existing non-recursive JSON bound before Zod traverses producer data. */
33
+ export function boundedToolLearningSchema(schema, maximumBytes) {
34
+ return z.preprocess((value, context) => {
35
+ try {
36
+ assertBoundedTaskJson(value, maximumBytes);
37
+ }
38
+ catch {
39
+ context.addIssue({
40
+ code: "custom",
41
+ message: "Tool learning data exceeds its JSON boundary.",
42
+ });
43
+ return z.NEVER;
44
+ }
45
+ return value;
46
+ }, schema);
47
+ }
48
+ export function toolLearningText(maximumBytes) {
49
+ return z
50
+ .string()
51
+ .max(maximumBytes)
52
+ .refine((value) => new TextEncoder().encode(value).byteLength <= maximumBytes, "Tool learning text exceeds its UTF-8 byte limit.");
53
+ }
54
+ export const ToolLearningStateSchema = boundedToolLearningSchema(z
55
+ .record(z.string().min(1).max(120), z.union([toolLearningText(2_000), z.number().finite(), z.boolean(), z.null()]))
56
+ .refine((value) => Object.keys(value).length <= 32, "Use at most 32 explicit state fields."), TOOL_LEARNING_LIMITS.stateBytes);
57
+ export const ToolLearningEnvironmentSchema = z
58
+ .object({
59
+ application: z.string().trim().min(1).max(200),
60
+ version: z.string().trim().min(1).max(200),
61
+ state: ToolLearningStateSchema,
62
+ fingerprint: ReleaseHashSchema,
63
+ })
64
+ .strict();
65
+ export const ToolLearningAssetSchema = z
66
+ .object({
67
+ id: ReleaseIdSchema,
68
+ contentHash: ReleaseHashSchema,
69
+ mediaType: z.enum(["text/plain", "application/json", "text/x-python", "text/x-diff"]),
70
+ sizeBytes: z.number().int().nonnegative().max(TOOL_LEARNING_LIMITS.assetBytes),
71
+ purpose: z.enum(["action", "result", "state", "verification"]),
72
+ })
73
+ .strict();
74
+ export const ToolLearningSanitizationSchema = z
75
+ .object({
76
+ policyRevision: z.number().int().positive(),
77
+ policyHash: ReleaseHashSchema,
78
+ redactedFields: z.number().int().nonnegative().max(10_000),
79
+ omittedFields: z.number().int().nonnegative().max(10_000),
80
+ truncated: z.boolean(),
81
+ })
82
+ .strict();
83
+ /** Hash only the validated public envelope; no raw hook/transcript data enters it. */
84
+ export function toolLearningContentHash(value, maximumBytes = TOOL_LEARNING_LIMITS.eventBytes) {
85
+ assertBoundedTaskJson(value, maximumBytes);
86
+ return contentHash(value);
87
+ }
@@ -1,4 +1,11 @@
1
1
  import { type JavaScriptIsolateInput } from "./javascript-isolate.js";
2
+ /** Created only by the trusted parent wall timer, never from guest error text.
3
+ * The process executor rejects with this error only after child exit. */
4
+ export declare class JavaScriptVerifierHostTimeoutError extends Error {
5
+ readonly timeoutMs: number;
6
+ readonly elapsedMs: number;
7
+ constructor(timeoutMs: number, elapsedMs: number);
8
+ }
2
9
  /** A Node subprocess owns the interpreter; completion always waits for its exit. */
3
10
  export declare function executeJavaScriptIsolateInProcess(input: JavaScriptIsolateInput & {
4
11
  stripTypeScript?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"javascript-isolate-process.d.ts","sourceRoot":"","sources":["../../src/javascript-isolate-process.ts"],"names":[],"mappings":"AACA,OAAO,EAAmE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGvI,oFAAoF;AACpF,wBAAsB,iCAAiC,CAAC,KAAK,EAAE,sBAAsB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CA0DvI"}
1
+ {"version":3,"file":"javascript-isolate-process.d.ts","sourceRoot":"","sources":["../../src/javascript-isolate-process.ts"],"names":[],"mappings":"AACA,OAAO,EAAmE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGvI;yEACyE;AACzE,qBAAa,kCAAmC,SAAQ,KAAK;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM;IAAlE,YAAqB,SAAS,EAAE,MAAM,EAAW,SAAS,EAAE,MAAM,EAGjE;CACF;AAED,oFAAoF;AACpF,wBAAsB,iCAAiC,CAAC,KAAK,EAAE,sBAAsB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CA8EvI"}
@@ -12,6 +12,8 @@ export declare class JavaScriptIsolateExecutionError extends Error {
12
12
  constructor(message: string);
13
13
  }
14
14
  /** Authored code is interpreter data, with no host functions or module loader. */
15
- export declare function executeJavaScriptIsolate(input: JavaScriptIsolateInput): Promise<unknown>;
15
+ export declare function executeJavaScriptIsolate(input: JavaScriptIsolateInput, host?: {
16
+ onExecutionReady(): void;
17
+ }): Promise<unknown>;
16
18
  export declare function validateJavaScriptIsolateInput(input: JavaScriptIsolateInput): void;
17
19
  //# sourceMappingURL=javascript-isolate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"javascript-isolate.d.ts","sourceRoot":"","sources":["../../src/javascript-isolate.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,UAAU,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;CAClE;AAED,qBAAa,+BAAgC,SAAQ,KAAK;IACxD,YAAY,OAAO,EAAE,MAAM,EAAoE;CAChG;AAED,kFAAkF;AAClF,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAuC9F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAKlF"}
1
+ {"version":3,"file":"javascript-isolate.d.ts","sourceRoot":"","sources":["../../src/javascript-isolate.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,UAAU,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;CAClE;AAED,qBAAa,+BAAgC,SAAQ,KAAK;IACxD,YAAY,OAAO,EAAE,MAAM,EAAoE;CAChG;AAED,kFAAkF;AAClF,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,sBAAsB,EAAE,IAAI,CAAC,EAAE;IAAE,gBAAgB,IAAI,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CA0CnI;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAKlF"}
@@ -1,5 +1,6 @@
1
1
  import type { executeJavaScriptVerifier } from "./javascript-verifier.js";
2
2
  import { type JavaScriptVerifierResult } from "./javascript-verifier-contract.js";
3
+ export { JavaScriptVerifierHostTimeoutError } from "./javascript-isolate-process.js";
3
4
  /** Resolves/rejects only after the execution owner has stopped the worker. */
4
5
  export declare function executeJavaScriptVerifierInWorker(input: Parameters<typeof executeJavaScriptVerifier>[0]): Promise<JavaScriptVerifierResult>;
5
6
  /** Uses a Node child process and waits for exit on success, failure, or cancellation. */
@@ -1 +1 @@
1
- {"version":3,"file":"javascript-verifier-node.d.ts","sourceRoot":"","sources":["../../src/javascript-verifier-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAiE,KAAK,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAIjJ,8EAA8E;AAC9E,wBAAsB,iCAAiC,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAGjJ;AAED,yFAAyF;AACzF,wBAAsB,kCAAkC,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAGlJ"}
1
+ {"version":3,"file":"javascript-verifier-node.d.ts","sourceRoot":"","sources":["../../src/javascript-verifier-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAiE,KAAK,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAGjJ,OAAO,EAAE,kCAAkC,EAAE,MAAM,iCAAiC,CAAC;AAErF,8EAA8E;AAC9E,wBAAsB,iCAAiC,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAGjJ;AAED,yFAAyF;AACzF,wBAAsB,kCAAkC,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAGlJ"}
@@ -25,6 +25,7 @@ export * from "./reward-fixture-executor.js";
25
25
  export * from "./iteration-reservation-contracts.js";
26
26
  export * from "./iteration-dispatch-contracts.js";
27
27
  export * from "./iteration-dispatch-worker.js";
28
+ export * from "./iteration-dispatch-deferral.js";
28
29
  export * from "./iteration-candidate-decision.js";
29
30
  export { resolveLearningTrainingParent } from "./iteration-training-parent.js";
30
31
  export * from "./schedule-contracts.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/learning/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAE,2BAA2B,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAChG,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/learning/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAE,2BAA2B,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAChG,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC"}