@openpond/evals 0.11.19 → 0.11.21

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 (83) hide show
  1. package/dist/connected-evidence/collector-coverage-contracts.js +160 -0
  2. package/dist/connected-evidence/contracts.js +1 -1
  3. package/dist/connected-evidence/imports.js +2 -1
  4. package/dist/connected-evidence/index.js +1 -0
  5. package/dist/connected-evidence/normalize.js +14 -4
  6. package/dist/execution-contracts.js +1 -1
  7. package/dist/javascript-isolate-node.js +2 -1
  8. package/dist/javascript-isolate-process-source.js +1 -1
  9. package/dist/javascript-isolate-process.js +2 -1
  10. package/dist/javascript-isolate.js +2 -1
  11. package/dist/javascript-verifier-worker-source.js +1 -1
  12. package/dist/native-conversations/codex-window-inventory.js +97 -0
  13. package/dist/native-conversations/collector-acquisition.js +149 -0
  14. package/dist/native-conversations/collector-branches.js +1 -0
  15. package/dist/native-conversations/collector-calendar-gate.js +19 -0
  16. package/dist/native-conversations/collector-contracts.js +4 -3
  17. package/dist/native-conversations/collector-coverage.js +100 -0
  18. package/dist/native-conversations/collector-cron.js +43 -0
  19. package/dist/native-conversations/collector-schedule.js +61 -0
  20. package/dist/native-conversations/collector-service-files.js +51 -0
  21. package/dist/native-conversations/collector-snapshots.js +70 -0
  22. package/dist/native-conversations/collector-source-cache.js +41 -0
  23. package/dist/native-conversations/collector-store.js +47 -8
  24. package/dist/native-conversations/collector.js +189 -254
  25. package/dist/native-conversations/history.js +44 -6
  26. package/dist/native-conversations/index.js +1 -0
  27. package/dist/native-conversations/location.js +4 -2
  28. package/dist/native-conversations/readiness.js +4 -0
  29. package/dist/native-conversations/supervisor.js +131 -81
  30. package/dist/native-conversations/titles.js +38 -0
  31. package/dist/sql-execution-node.js +2 -1
  32. package/dist/tasksets.js +1 -1
  33. package/dist/types/connected-evidence/collector-coverage-contracts.d.ts +98 -0
  34. package/dist/types/connected-evidence/collector-coverage-contracts.d.ts.map +1 -0
  35. package/dist/types/connected-evidence/contracts.d.ts.map +1 -1
  36. package/dist/types/connected-evidence/imports.d.ts +1 -0
  37. package/dist/types/connected-evidence/imports.d.ts.map +1 -1
  38. package/dist/types/connected-evidence/index.d.ts +1 -0
  39. package/dist/types/connected-evidence/index.d.ts.map +1 -1
  40. package/dist/types/connected-evidence/normalize.d.ts +3 -0
  41. package/dist/types/connected-evidence/normalize.d.ts.map +1 -1
  42. package/dist/types/javascript-isolate-node.d.ts.map +1 -1
  43. package/dist/types/javascript-isolate-process.d.ts.map +1 -1
  44. package/dist/types/javascript-isolate.d.ts.map +1 -1
  45. package/dist/types/native-conversations/codex-window-inventory.d.ts +12 -0
  46. package/dist/types/native-conversations/codex-window-inventory.d.ts.map +1 -0
  47. package/dist/types/native-conversations/collector-acquisition.d.ts +17 -0
  48. package/dist/types/native-conversations/collector-acquisition.d.ts.map +1 -0
  49. package/dist/types/native-conversations/collector-branches.d.ts.map +1 -1
  50. package/dist/types/native-conversations/collector-calendar-gate.d.ts +9 -0
  51. package/dist/types/native-conversations/collector-calendar-gate.d.ts.map +1 -0
  52. package/dist/types/native-conversations/collector-contracts.d.ts +45 -5
  53. package/dist/types/native-conversations/collector-contracts.d.ts.map +1 -1
  54. package/dist/types/native-conversations/collector-coverage.d.ts +62 -0
  55. package/dist/types/native-conversations/collector-coverage.d.ts.map +1 -0
  56. package/dist/types/native-conversations/collector-cron.d.ts +20 -0
  57. package/dist/types/native-conversations/collector-cron.d.ts.map +1 -0
  58. package/dist/types/native-conversations/collector-schedule.d.ts +13 -0
  59. package/dist/types/native-conversations/collector-schedule.d.ts.map +1 -0
  60. package/dist/types/native-conversations/collector-service-files.d.ts +20 -0
  61. package/dist/types/native-conversations/collector-service-files.d.ts.map +1 -0
  62. package/dist/types/native-conversations/collector-snapshots.d.ts +25 -0
  63. package/dist/types/native-conversations/collector-snapshots.d.ts.map +1 -0
  64. package/dist/types/native-conversations/collector-source-cache.d.ts +31 -0
  65. package/dist/types/native-conversations/collector-source-cache.d.ts.map +1 -0
  66. package/dist/types/native-conversations/collector-store.d.ts +11 -2
  67. package/dist/types/native-conversations/collector-store.d.ts.map +1 -1
  68. package/dist/types/native-conversations/collector.d.ts +5 -1
  69. package/dist/types/native-conversations/collector.d.ts.map +1 -1
  70. package/dist/types/native-conversations/history.d.ts +7 -0
  71. package/dist/types/native-conversations/history.d.ts.map +1 -1
  72. package/dist/types/native-conversations/index.d.ts +1 -0
  73. package/dist/types/native-conversations/index.d.ts.map +1 -1
  74. package/dist/types/native-conversations/location.d.ts.map +1 -1
  75. package/dist/types/native-conversations/readiness.d.ts +5 -0
  76. package/dist/types/native-conversations/readiness.d.ts.map +1 -0
  77. package/dist/types/native-conversations/supervisor.d.ts +4 -3
  78. package/dist/types/native-conversations/supervisor.d.ts.map +1 -1
  79. package/dist/types/native-conversations/titles.d.ts +4 -0
  80. package/dist/types/native-conversations/titles.d.ts.map +1 -0
  81. package/dist/types/sql-execution-node.d.ts.map +1 -1
  82. package/package.json +4 -3
  83. package/schemas/learning/v1/package.schema.json +0 -1
@@ -0,0 +1,160 @@
1
+ import { z } from "zod";
2
+ import { contentHash } from "@openpond/harness";
3
+ const Id = z.string().trim().min(1).max(500);
4
+ const Hash = z.string().regex(/^[a-f0-9]{64}$/);
5
+ const Timestamp = z.iso.datetime();
6
+ const Count = z.number().int().nonnegative().max(1_000_000);
7
+ export const CollectorCoverageSessionSchema = z
8
+ .object({
9
+ sourceKeyHash: Hash,
10
+ nativeRevisionHash: Hash.nullable(),
11
+ state: z.enum(["reading", "admitted", "skipped", "failed"]),
12
+ reason: z
13
+ .enum([
14
+ "no_eligible_boundaries",
15
+ "native_session_not_ready",
16
+ "source_read_failed",
17
+ "source_revision_unavailable",
18
+ ])
19
+ .nullable(),
20
+ unknownTimeBoundaries: Count,
21
+ normalized: z
22
+ .array(z
23
+ .object({
24
+ sessionHash: Hash,
25
+ boundaries: z
26
+ .array(z
27
+ .object({ id: Id, inputHash: Hash, revisionHash: Hash, occurredAt: Timestamp })
28
+ .strict())
29
+ .max(5_000),
30
+ })
31
+ .strict())
32
+ .max(1_000),
33
+ })
34
+ .strict();
35
+ export const CollectorCoverageManifestSchema = z
36
+ .object({
37
+ schemaVersion: z.literal("openpond.collectorCoverageManifest.v1"),
38
+ jobId: Id,
39
+ connectionId: Id,
40
+ connectionRevision: z.number().int().positive(),
41
+ machineId: Id,
42
+ sourceInstanceId: Id,
43
+ from: Timestamp.nullable(),
44
+ to: Timestamp,
45
+ startedAt: Timestamp,
46
+ finishedAt: Timestamp.nullable(),
47
+ listingComplete: z.boolean(),
48
+ pendingOperations: Count,
49
+ sessions: z.array(CollectorCoverageSessionSchema).max(10_000),
50
+ })
51
+ .strict()
52
+ .superRefine((value, ctx) => {
53
+ if (value.from !== null && Date.parse(value.from) >= Date.parse(value.to))
54
+ ctx.addIssue({
55
+ code: "custom",
56
+ message: "Collector source window is empty.",
57
+ });
58
+ if (value.finishedAt !== null &&
59
+ Date.parse(value.finishedAt) < Date.parse(value.startedAt))
60
+ ctx.addIssue({
61
+ code: "custom",
62
+ message: "Collector finish time precedes its start.",
63
+ });
64
+ if (new Set(value.sessions.map((session) => session.sourceKeyHash)).size !==
65
+ value.sessions.length)
66
+ ctx.addIssue({
67
+ code: "custom",
68
+ message: "Collector source inventory is duplicated.",
69
+ });
70
+ let boundaries = 0;
71
+ for (const session of value.sessions)
72
+ for (const normalized of session.normalized) {
73
+ boundaries += normalized.boundaries.length;
74
+ if (new Set(normalized.boundaries.map((boundary) => boundary.id)).size !==
75
+ normalized.boundaries.length)
76
+ ctx.addIssue({
77
+ code: "custom",
78
+ message: "Normalized source boundaries are duplicated.",
79
+ });
80
+ for (const boundary of normalized.boundaries)
81
+ if (Date.parse(boundary.occurredAt) >= Date.parse(value.to) ||
82
+ (value.from !== null &&
83
+ Date.parse(boundary.occurredAt) < Date.parse(value.from)))
84
+ ctx.addIssue({
85
+ code: "custom",
86
+ message: "Eligible boundary is outside the declared event-time window.",
87
+ });
88
+ }
89
+ if (boundaries > 20_000)
90
+ ctx.addIssue({
91
+ code: "custom",
92
+ message: "Collector coverage exceeds its bounded boundary inventory.",
93
+ });
94
+ });
95
+ export const CollectorCoverageSummarySchema = z
96
+ .object({
97
+ jobId: Id,
98
+ manifestHash: Hash,
99
+ sourceInventoryHash: Hash,
100
+ eligibleBoundaryHash: Hash,
101
+ from: Timestamp.nullable(),
102
+ to: Timestamp,
103
+ finishedAt: Timestamp.nullable(),
104
+ conversations: Count,
105
+ eligibleTurns: Count,
106
+ admittedSessions: Count,
107
+ skippedSessions: Count,
108
+ failedSessions: Count,
109
+ unknownTimeBoundaries: Count,
110
+ pendingOperations: Count,
111
+ listingComplete: z.boolean(),
112
+ complete: z.boolean(),
113
+ })
114
+ .strict();
115
+ export function hashCollectorEligibleBoundaries(input) {
116
+ const boundaries = new Map(input.map((boundary) => [
117
+ JSON.stringify([boundary.id, boundary.inputHash, boundary.revisionHash]),
118
+ { id: boundary.id, inputHash: boundary.inputHash, revisionHash: boundary.revisionHash },
119
+ ]));
120
+ const ordered = [...boundaries]
121
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
122
+ .map(([, boundary]) => boundary);
123
+ return { hash: contentHash(ordered), count: ordered.length };
124
+ }
125
+ export function summarizeCollectorCoverage(raw) {
126
+ const manifest = CollectorCoverageManifestSchema.parse(raw);
127
+ const boundaries = hashCollectorEligibleBoundaries(manifest.sessions.flatMap((session) => session.normalized.flatMap((normalized) => normalized.boundaries)));
128
+ const unknownTimeBoundaries = manifest.sessions.reduce((sum, session) => sum + session.unknownTimeBoundaries, 0);
129
+ return CollectorCoverageSummarySchema.parse({
130
+ jobId: manifest.jobId,
131
+ manifestHash: contentHash(manifest),
132
+ sourceInventoryHash: contentHash(manifest.sessions
133
+ .map((session) => ({
134
+ sourceKeyHash: session.sourceKeyHash,
135
+ nativeRevisionHash: session.nativeRevisionHash,
136
+ snapshots: session.normalized.map((normalized) => normalized.sessionHash),
137
+ }))
138
+ .sort((a, b) => a.sourceKeyHash.localeCompare(b.sourceKeyHash))),
139
+ eligibleBoundaryHash: boundaries.hash,
140
+ from: manifest.from,
141
+ to: manifest.to,
142
+ finishedAt: manifest.finishedAt,
143
+ conversations: manifest.sessions.length,
144
+ eligibleTurns: boundaries.count,
145
+ admittedSessions: manifest.sessions.filter((session) => session.state === "admitted").length,
146
+ skippedSessions: manifest.sessions.filter((session) => session.state === "skipped").length,
147
+ failedSessions: manifest.sessions.filter((session) => session.state === "failed").length,
148
+ unknownTimeBoundaries,
149
+ pendingOperations: manifest.pendingOperations,
150
+ listingComplete: manifest.listingComplete,
151
+ complete: manifest.finishedAt !== null &&
152
+ manifest.listingComplete &&
153
+ manifest.pendingOperations === 0 &&
154
+ unknownTimeBoundaries === 0 &&
155
+ manifest.sessions.every((session) => session.nativeRevisionHash !== null &&
156
+ (session.state === "admitted" ||
157
+ (session.state === "skipped" &&
158
+ session.reason === "no_eligible_boundaries"))),
159
+ });
160
+ }
@@ -3,7 +3,7 @@ import { contentHash } from "@openpond/harness";
3
3
  export const CONNECTED_EVIDENCE_VERSION = "openpond.connectedEvidence.v1";
4
4
  export const CONNECTED_NORMALIZER_VERSION = "connected-evidence-1";
5
5
  export const CONNECTED_EVIDENCE_LIMITS = { files: 100, sourceBytes: 32 * 1024 * 1024, decodedBytes: 64 * 1024 * 1024,
6
- lineBytes: 2 * 1024 * 1024, events: 100_000, sessions: 1_000, boundaries: 5_000, evaluatorBytes: 2 * 1024 * 1024 };
6
+ lineBytes: 64 * 1024 * 1024, events: 100_000, sessions: 1_000, boundaries: 5_000, evaluatorBytes: 2 * 1024 * 1024 };
7
7
  const Id = z.string().min(1).max(500);
8
8
  const Hash = z.string().regex(/^[a-f0-9]{64}$/);
9
9
  const Time = z.string().datetime().nullable();
@@ -1,6 +1,6 @@
1
1
  import { contentHash } from "@openpond/harness";
2
2
  import { CONNECTED_EVIDENCE_LIMITS, CONNECTED_NORMALIZER_VERSION, } from "./contracts.js";
3
- import { connectedJsonLines, normalizeConnectedSession } from "./normalize.js";
3
+ import { connectedJsonLines, normalizeConnectedSession, ConnectedSessionWithoutUserRequestError } from "./normalize.js";
4
4
  import { parseGrokBuildSession } from "./sources/grok-build.js";
5
5
  import { parsePiSession } from "./sources/pi.js";
6
6
  import { parseOpenCodeSession } from "./sources/opencode.js";
@@ -55,6 +55,7 @@ export function previewAgentImport(input) {
55
55
  catch (error) {
56
56
  issues.push({
57
57
  file,
58
+ ...(error instanceof ConnectedSessionWithoutUserRequestError ? { code: "no_user_request" } : {}),
58
59
  message: error instanceof Error ? error.message : "Unsupported session.",
59
60
  });
60
61
  }
@@ -3,3 +3,4 @@ export * from "./normalize.js";
3
3
  export * from "./imports.js";
4
4
  export * from "./usage-summary.js";
5
5
  export * from "./python-correctness.js";
6
+ export * from "./collector-coverage-contracts.js";
@@ -1,5 +1,8 @@
1
- import { contentHash } from "@openpond/harness";
1
+ import { contentHash, contentHashArrayPrefixes } from "@openpond/harness";
2
2
  import { CONNECTED_EVIDENCE_LIMITS, CONNECTED_EVIDENCE_VERSION, CONNECTED_NORMALIZER_VERSION, ConnectedSessionSchema, hasRecordedConnectedAnswer } from "./contracts.js";
3
+ export class ConnectedSessionWithoutUserRequestError extends Error {
4
+ constructor() { super("The session has no retained user request."); }
5
+ }
3
6
  export function connectedTimestamp(value, units = "milliseconds") {
4
7
  if (typeof value !== "number" && typeof value !== "string")
5
8
  return null;
@@ -17,10 +20,12 @@ export function normalizeConnectedSession(input) {
17
20
  throw new Error("connected_duplicate_event");
18
21
  const starts = events.flatMap((event, index) => event.kind === "message" && event.role === "user" ? [index] : []);
19
22
  if (!starts.length)
20
- throw new Error("The session has no retained user request.");
23
+ throw new ConnectedSessionWithoutUserRequestError();
21
24
  if (starts.length + (input.includeConversation === false ? 0 : 1) > CONNECTED_EVIDENCE_LIMITS.boundaries)
22
25
  throw new Error("connected_boundary_limit");
23
26
  const familyKey = `family-${contentHash([input.origin, ...(input.acquisition ? [input.acquisition.sourceInstanceId] : []), input.parentSessionId ?? input.sessionId]).slice(0, 32)}`;
27
+ const inputHashes = contentHashArrayPrefixes(events, starts.map(start => start + 1));
28
+ const firstCompaction = events.findIndex(event => event.kind === "compaction");
24
29
  const boundaries = starts.map((start, position) => {
25
30
  const end = starts[position + 1] ?? events.length;
26
31
  const observed = events.slice(start + 1, end);
@@ -32,12 +37,12 @@ export function normalizeConnectedSession(input) {
32
37
  const terminal = [...observed].reverse().find(event => event.kind === "terminal");
33
38
  const status = terminal && typeof terminal.content === "object" && terminal.content !== null && !Array.isArray(terminal.content)
34
39
  ? terminal.content.status : null;
35
- const compacted = events.slice(0, start + 1).some(event => event.kind === "compaction");
40
+ const compacted = firstCompaction >= 0 && firstCompaction <= start;
36
41
  const unknown = observed.some(event => event.kind === "unknown");
37
42
  return {
38
43
  id: `case-${contentHash([input.origin, ...(input.acquisition ? [input.acquisition.sourceInstanceId] : []), input.sessionId, input.branchId ?? null, events[start].id]).slice(0, 40)}`,
39
44
  familyKey, projection: "turn", requestEventId: events[start].id, start, end,
40
- inputHash: contentHash(events.slice(0, start + 1)), outputHash: answer ? contentHash(answer.content) : null,
45
+ inputHash: inputHashes[position], outputHash: answer ? contentHash(answer.content) : null,
41
46
  revisionHash: contentHash(observed), terminal: status === "completed" || status === "failed" || status === "cancelled" ? status : "unknown",
42
47
  coverage: { answer: Boolean(answer), context: input.contextComplete === false ? "unknown" : compacted ? "compacted" : "retained",
43
48
  process: !tools.length ? unknown ? "partial" : "absent" : incomplete || unknown ? "partial" : "retained",
@@ -69,6 +74,11 @@ export function normalizeConnectedSession(input) {
69
74
  return session;
70
75
  }
71
76
  export function connectedJsonLines(file) {
77
+ // Native tool results and image blocks can occupy one large JSONL record.
78
+ // Bound the whole decoded input before parsing, rather than rejecting valid
79
+ // evidence solely because its exporter uses a single physical line.
80
+ if (new TextEncoder().encode(file.text).length > CONNECTED_EVIDENCE_LIMITS.decodedBytes)
81
+ throw new Error("Decoded source files exceed 64 MiB.");
72
82
  const lines = file.text.replace(/^\uFEFF/u, "").split(/\r?\n/u);
73
83
  if (lines.length > CONNECTED_EVIDENCE_LIMITS.events + 1)
74
84
  throw new Error("connected_event_limit");
@@ -83,7 +83,7 @@ export const VerifierSetReleaseContentSchema = z.object({
83
83
  schemaVersion: z.literal("openpond.verifierSetRelease.v1"),
84
84
  id: ReleaseIdSchema,
85
85
  revision: z.number().int().positive(),
86
- graders: z.array(GraderSpecSchema).min(1).max(1_000),
86
+ graders: z.array(GraderSpecSchema).max(1_000),
87
87
  isolation: z.object({
88
88
  processBoundary: z.enum(["same_process", "isolated_process", "container"]),
89
89
  networkPolicy: z.literal("none"),
@@ -1,11 +1,12 @@
1
1
  import { Worker } from "node:worker_threads";
2
- import { javascriptVerifierWorkerSource } from "./javascript-verifier-worker-source.js";
3
2
  import { validateJavaScriptIsolateInput } from "./javascript-isolate.js";
4
3
  import { assertBoundedTaskJson } from "./task-schema.js";
5
4
  /** Both environment steps and graders settle only after their worker stops. */
6
5
  export async function executeJavaScriptIsolateInWorker(input) {
7
6
  input.signal?.throwIfAborted();
8
7
  validateJavaScriptIsolateInput(input);
8
+ const { javascriptVerifierWorkerSource } = await import("./javascript-verifier-worker-source.js");
9
+ input.signal?.throwIfAborted();
9
10
  const signal = input.signal;
10
11
  const workerData = { source: input.source, exportName: input.exportName, value: input.value, timeoutMs: input.timeoutMs, maxResultBytes: input.maxResultBytes, deterministic: input.deterministic === true, errorPrefix: input.errorPrefix };
11
12
  const error = (suffix) => new Error(`${input.errorPrefix}_${suffix}`);