humanish 0.88.2 → 0.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +8 -0
  2. package/dist/export-bundle.js +6 -0
  3. package/dist/export-bundle.js.map +1 -1
  4. package/dist/export.js +67 -10
  5. package/dist/export.js.map +1 -1
  6. package/dist/feedback.d.ts +10 -0
  7. package/dist/feedback.js +58 -1
  8. package/dist/feedback.js.map +1 -1
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.js +2 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/observer-app.html +10 -9
  13. package/dist/observer.d.ts +2 -0
  14. package/dist/observer.js +52 -5
  15. package/dist/observer.js.map +1 -1
  16. package/dist/pricing.js +2 -2
  17. package/dist/pricing.js.map +1 -1
  18. package/dist/program.js +146 -3
  19. package/dist/program.js.map +1 -1
  20. package/dist/run.d.ts +3 -1
  21. package/dist/run.js +46 -18
  22. package/dist/run.js.map +1 -1
  23. package/dist/study-analysis-engine.d.ts +34 -0
  24. package/dist/study-analysis-engine.js +217 -0
  25. package/dist/study-analysis-engine.js.map +1 -0
  26. package/dist/study-analysis-evidence.d.ts +27 -0
  27. package/dist/study-analysis-evidence.js +420 -0
  28. package/dist/study-analysis-evidence.js.map +1 -0
  29. package/dist/study-analysis-provider.d.ts +38 -0
  30. package/dist/study-analysis-provider.js +140 -0
  31. package/dist/study-analysis-provider.js.map +1 -0
  32. package/dist/study-analysis-service.d.ts +45 -0
  33. package/dist/study-analysis-service.js +207 -0
  34. package/dist/study-analysis-service.js.map +1 -0
  35. package/dist/study-analysis-sharing.d.ts +11 -0
  36. package/dist/study-analysis-sharing.js +27 -0
  37. package/dist/study-analysis-sharing.js.map +1 -0
  38. package/dist/study-analysis-store.d.ts +30 -0
  39. package/dist/study-analysis-store.js +343 -0
  40. package/dist/study-analysis-store.js.map +1 -0
  41. package/dist/study-analysis-validation.d.ts +448 -0
  42. package/dist/study-analysis-validation.js +331 -0
  43. package/dist/study-analysis-validation.js.map +1 -0
  44. package/dist/study-analysis.d.ts +167 -0
  45. package/dist/study-analysis.js +4 -0
  46. package/dist/study-analysis.js.map +1 -0
  47. package/docs/architecture/observer.md +10 -1
  48. package/docs/contracts/feedback.md +9 -3
  49. package/docs/contracts/schemas.md +4 -1
  50. package/docs/contracts/study-analysis.md +150 -0
  51. package/docs/goals/current.md +4 -3
  52. package/docs/ramp/README.md +9 -2
  53. package/docs/release/0.89.0-study-findings.md +79 -0
  54. package/package.json +3 -2
@@ -0,0 +1,420 @@
1
+ import { cuaGoalSource } from "./actor-goal-source.js";
2
+ import { createHash } from "node:crypto";
3
+ import { screenshotEvidenceError } from "./image-evidence.js";
4
+ import { digestStudyAnalysisInput, hashStudyAnalysisValue, validateStudyAnalysisInputMetadata } from "./study-analysis-validation.js";
5
+ import { constants } from "node:fs";
6
+ import { lstat, open, realpath } from "node:fs/promises";
7
+ import path from "node:path";
8
+ import { isPathInside, validatePreparedRunRootIdentity } from "./run-paths.js";
9
+ import { assertPreparedSelectedOutputDirectory } from "./selected-output-paths.js";
10
+ /** Analysis inputs are retained local artifacts, never URLs or caller-selected outputs. */
11
+ export function isStudyEvidencePath(value) {
12
+ if (!value || value.length > 1024)
13
+ return false;
14
+ try {
15
+ encodeURIComponent(value);
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ let checked = value;
21
+ for (let attempt = 0; attempt < 5; attempt++) {
22
+ if (/[\\:\x00-\x1f\x7f]/.test(checked) || checked.startsWith("/")
23
+ || checked.split("/").some((part) => part === "" || part === "." || part === ".."))
24
+ return false;
25
+ let decoded;
26
+ try {
27
+ decoded = decodeURIComponent(checked);
28
+ }
29
+ catch {
30
+ return !/%[0-9a-f]{2}/i.test(checked);
31
+ }
32
+ if (decoded === checked)
33
+ return true;
34
+ if (decoded.split("/").length !== checked.split("/").length)
35
+ return false;
36
+ checked = decoded;
37
+ }
38
+ return false;
39
+ }
40
+ /**
41
+ * Bounded companion to readContainedRegularFile. A growing or swapped file must
42
+ * not turn an analysis budget into an unbounded read. No returned bytes have
43
+ * authority to select another file or initiate a network request.
44
+ */
45
+ export async function readBoundedStudyFile(root, relativePath, maxBytes) {
46
+ if (!isStudyEvidencePath(relativePath) || !Number.isSafeInteger(maxBytes) || maxBytes < 1)
47
+ return null;
48
+ const validateRoot = async () => {
49
+ if ("physicalRunRoot" in root) {
50
+ await validatePreparedRunRootIdentity(root);
51
+ return root.physicalRunRoot;
52
+ }
53
+ await assertPreparedSelectedOutputDirectory(root);
54
+ return root.physicalPath;
55
+ };
56
+ try {
57
+ const physicalRoot = await validateRoot();
58
+ const candidate = path.join(physicalRoot, relativePath);
59
+ if (!isPathInside(physicalRoot, candidate) || candidate === physicalRoot)
60
+ return null;
61
+ const validateParents = async () => {
62
+ let current = physicalRoot;
63
+ for (const segment of relativePath.split("/").slice(0, -1)) {
64
+ current = path.join(current, segment);
65
+ const info = await lstat(current);
66
+ if (!info.isDirectory() || info.isSymbolicLink())
67
+ throw new Error("Unsafe analysis input directory.");
68
+ }
69
+ };
70
+ await validateParents();
71
+ const before = await lstat(candidate, { bigint: true });
72
+ if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1n || before.size > BigInt(maxBytes))
73
+ return null;
74
+ if (await realpath(candidate) !== candidate)
75
+ return null;
76
+ // O_NONBLOCK avoids hanging if a regular leaf is raced into a special file.
77
+ const handle = await open(candidate, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
78
+ try {
79
+ const opened = await handle.stat({ bigint: true });
80
+ if (!opened.isFile() || opened.nlink !== 1n || opened.dev !== before.dev || opened.ino !== before.ino
81
+ || opened.size !== before.size || opened.mtimeNs !== before.mtimeNs)
82
+ return null;
83
+ const chunks = [];
84
+ let total = 0;
85
+ while (total <= maxBytes) {
86
+ const chunk = Buffer.allocUnsafe(Math.min(64 * 1024, maxBytes + 1 - total));
87
+ const { bytesRead } = await handle.read(chunk, 0, chunk.length, null);
88
+ if (bytesRead === 0)
89
+ break;
90
+ total += bytesRead;
91
+ if (total > maxBytes)
92
+ return null;
93
+ chunks.push(chunk.subarray(0, bytesRead));
94
+ }
95
+ const after = await handle.stat({ bigint: true });
96
+ if (after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs
97
+ || after.nlink !== 1n || total !== Number(before.size))
98
+ return null;
99
+ if (await validateRoot() !== physicalRoot)
100
+ return null;
101
+ await validateParents();
102
+ const final = await lstat(candidate, { bigint: true });
103
+ if (!final.isFile() || final.isSymbolicLink() || final.dev !== before.dev || final.ino !== before.ino
104
+ || final.nlink !== 1n || final.size !== before.size || final.mtimeNs !== before.mtimeNs)
105
+ return null;
106
+ return Buffer.concat(chunks, total);
107
+ }
108
+ finally {
109
+ await handle.close();
110
+ }
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ export const STUDY_EVIDENCE_LIMITS = Object.freeze({
117
+ participants: 16, evidence: 800, captures: 40, textBytes: 160 * 1024,
118
+ imageBytes: 8 * 1024 * 1024, totalImageBytes: 20 * 1024 * 1024,
119
+ sourceBytes: 16 * 1024 * 1024
120
+ });
121
+ const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
122
+ const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
123
+ const stamp = (value) => typeof value === "string" && Number.isFinite(Date.parse(value))
124
+ ? new Date(value).toISOString() : null;
125
+ const itemText = (item) => ["message", "reasoning"].includes(item.kind) && item.text !== undefined
126
+ ? item.text : [item.title, item.text].filter((entry) => entry !== undefined && entry !== "").join("\n");
127
+ const itemsFor = (stream) => stream.actor?.items ?? [];
128
+ function parseSource(prepared, bytes) {
129
+ if (bytes.length > STUDY_EVIDENCE_LIMITS.sourceBytes)
130
+ throw new Error("ANALYSIS_SOURCE_TOO_LARGE");
131
+ const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
132
+ if (!object(value) || value.schema !== "humanish.run-bundle.v1"
133
+ || value.runId !== path.basename(prepared.physicalRunRoot)
134
+ || !Array.isArray(value.streams) || value.streams.length > 128 || !Array.isArray(value.events)
135
+ || value.events.length > 100000)
136
+ throw new Error("ANALYSIS_SOURCE_INVALID");
137
+ const ids = new Set();
138
+ for (const stream of value.streams) {
139
+ if (!object(stream) || typeof stream.id !== "string" || stream.id.length === 0 || stream.id.length > 256
140
+ || ids.has(stream.id) || typeof stream.label !== "string" || typeof stream.status !== "string") {
141
+ throw new Error("ANALYSIS_SOURCE_INVALID");
142
+ }
143
+ ids.add(stream.id);
144
+ const actor = stream.actor;
145
+ if (actor !== undefined && (!object(actor) || !Array.isArray(actor.items) || actor.items.length > 100000)) {
146
+ throw new Error("ANALYSIS_SOURCE_INVALID");
147
+ }
148
+ const eventIds = new Set();
149
+ for (const item of object(actor) ? actor.items : []) {
150
+ if (!object(item) || typeof item.id !== "string" || item.id.length === 0 || item.id.length > 256
151
+ || eventIds.has(item.id) || typeof item.kind !== "string" || typeof item.title !== "string"
152
+ || (item.text !== undefined && typeof item.text !== "string"))
153
+ throw new Error("ANALYSIS_SOURCE_INVALID");
154
+ eventIds.add(item.id);
155
+ }
156
+ }
157
+ for (const event of value.events) {
158
+ if (!object(event) || typeof event.id !== "string" || typeof event.message !== "string"
159
+ || typeof event.type !== "string")
160
+ throw new Error("ANALYSIS_SOURCE_INVALID");
161
+ }
162
+ return value;
163
+ }
164
+ function boundedText(value, maxBytes) {
165
+ if (Buffer.byteLength(value) <= maxBytes)
166
+ return value;
167
+ let output = "";
168
+ let bytes = 0;
169
+ for (const char of value) {
170
+ const size = Buffer.byteLength(char);
171
+ if (bytes + size > maxBytes)
172
+ break;
173
+ output += char;
174
+ bytes += size;
175
+ }
176
+ return output;
177
+ }
178
+ // Count the same frame declarations as Observer even when analysis omits their bytes.
179
+ function isObserverCapturePath(value) {
180
+ if (/^data:image\/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/.test(value))
181
+ return true;
182
+ if (!value || value.length > 8192)
183
+ return false;
184
+ try {
185
+ encodeURIComponent(value);
186
+ }
187
+ catch {
188
+ return false;
189
+ }
190
+ let checked = value;
191
+ for (let attempt = 0; attempt < 5; attempt++) {
192
+ if (/^[\\/]|[\\\u0000-\u001f\u007f]|^[a-z][a-z\d+.-]*:/i.test(checked)
193
+ || checked.split("/").some((part) => part === "." || part === ".." || part === ""))
194
+ return false;
195
+ let decoded;
196
+ try {
197
+ decoded = decodeURIComponent(checked);
198
+ }
199
+ catch {
200
+ return !/%[0-9a-f]{2}/i.test(checked);
201
+ }
202
+ if (decoded === checked)
203
+ return true;
204
+ if (decoded.split("/").length !== checked.split("/").length)
205
+ return false;
206
+ checked = decoded;
207
+ }
208
+ return false;
209
+ }
210
+ function participantAssignment(stream) {
211
+ if (stream.assignment === undefined)
212
+ return null;
213
+ return [stream.assignment.mission, stream.assignment.focus,
214
+ ...(stream.assignment.tasks ?? []).map((task) => `Task ${JSON.stringify(task.id)}: ${task.goal}`)]
215
+ .filter((entry) => typeof entry === "string").join("\n");
216
+ }
217
+ function participantSource(stream) {
218
+ const assignment = participantAssignment(stream);
219
+ const actor = stream.actor;
220
+ return {
221
+ streamId: stream.id,
222
+ label: boundedText(stream.label, 1000),
223
+ assignment: assignment === null ? null : boundedText(assignment, 8000),
224
+ recordedStatus: stream.status,
225
+ recordedReason: actor?.reason === undefined ? null : boundedText(actor.reason, 4000),
226
+ provenance: {
227
+ actorStatus: actor?.status ?? null,
228
+ completionReason: actor?.completionReason ?? null,
229
+ stopCause: actor?.stopCause ?? null,
230
+ goalSource: cuaGoalSource(actor, stream.status) ?? null,
231
+ declaredOutcome: actor?.declaredOutcome ?? null,
232
+ taskOutcomes: actor?.taskFunnel === undefined ? null : actor.taskFunnel.tasks.map((task) => ({
233
+ taskId: task.id, completed: task.completed, observable: task.observable,
234
+ inputsObserved: task.inputsObserved ?? null, turn: task.turn ?? null
235
+ }))
236
+ }
237
+ };
238
+ }
239
+ function sourceEntries(bundle, stream) {
240
+ const items = itemsFor(stream);
241
+ const captures = items.filter((item) => item.kind === "screenshot" && object(item.screenshotRef)
242
+ && typeof item.screenshotRef.path === "string" && isObserverCapturePath(item.screenshotRef.path));
243
+ const frameIds = new Set(captures.map((item) => item.id));
244
+ const firstAt = stamp(captures[0]?.at);
245
+ let frame = -1;
246
+ const entries = [];
247
+ for (const item of items) {
248
+ const capturePath = item.kind === "screenshot" && object(item.screenshotRef)
249
+ && typeof item.screenshotRef.path === "string" && isStudyEvidencePath(item.screenshotRef.path)
250
+ ? item.screenshotRef.path : null;
251
+ if (frameIds.has(item.id))
252
+ frame++;
253
+ const at = stamp(item.at);
254
+ const delta = at !== null && firstAt !== null ? Date.parse(at) - Date.parse(firstAt) : null;
255
+ entries.push({ eventId: item.id, kind: item.kind, text: itemText(item),
256
+ quoteEligible: ["message", "reasoning"].includes(item.kind) && typeof item.text === "string",
257
+ at, elapsedMs: delta !== null && delta >= 0 ? delta : null,
258
+ frame: captures.length > 0 ? Math.max(0, frame) : null, capturePath });
259
+ }
260
+ const runEventIds = new Set();
261
+ for (const event of bundle.events.filter((entry) => entry.streamId === stream.id
262
+ || (entry.streamId === undefined && entry.simId === stream.simId))) {
263
+ if (runEventIds.has(event.id))
264
+ throw new Error("ANALYSIS_SOURCE_EVENT_DUPLICATE");
265
+ runEventIds.add(event.id);
266
+ entries.push({ eventId: event.id, kind: `run_event:${event.type}`, text: event.message,
267
+ quoteEligible: false, at: stamp(event.at), elapsedMs: null, frame: null, capturePath: null });
268
+ }
269
+ return entries;
270
+ }
271
+ /** Select once from retained source. Models receive no filesystem or network resolver. */
272
+ export async function captureStudyEvidence(prepared, bundleBytes, requested = {}) {
273
+ const limits = { ...STUDY_EVIDENCE_LIMITS, ...requested };
274
+ for (const key of Object.keys(STUDY_EVIDENCE_LIMITS)) {
275
+ if (!Number.isSafeInteger(limits[key]) || limits[key] < 1 || limits[key] > STUDY_EVIDENCE_LIMITS[key]) {
276
+ throw new Error("ANALYSIS_INPUT_LIMIT_INVALID");
277
+ }
278
+ }
279
+ if (bundleBytes.length > limits.sourceBytes)
280
+ throw new Error("ANALYSIS_SOURCE_TOO_LARGE");
281
+ const current = await readBoundedStudyFile(prepared, "run.json", limits.sourceBytes);
282
+ if (!current || !current.equals(bundleBytes))
283
+ throw new Error("ANALYSIS_SOURCE_CHANGED");
284
+ const bundle = parseSource(prepared, bundleBytes);
285
+ if (bundle.streams.some((stream) => stream.liveActor !== undefined
286
+ || ["running", "pending", "queued", "starting", "preparing", "not_started", "suspended"].includes(stream.status))) {
287
+ throw new Error("ANALYSIS_RUN_UNFINISHED");
288
+ }
289
+ const selected = bundle.streams.slice(0, limits.participants);
290
+ const evidence = [];
291
+ const images = [];
292
+ const omissions = new Set();
293
+ let textBytes = 0;
294
+ let imageBytes = 0;
295
+ const participants = selected.map((stream) => {
296
+ const participant = participantSource(stream);
297
+ const assignment = participantAssignment(stream);
298
+ if (participant.label !== stream.label || participant.assignment !== assignment
299
+ || participant.recordedReason !== (stream.actor?.reason ?? null))
300
+ omissions.add("Participant context exceeded the text limit.");
301
+ textBytes += Buffer.byteLength(JSON.stringify(participant));
302
+ return participant;
303
+ });
304
+ if (textBytes > limits.textBytes)
305
+ throw new Error("ANALYSIS_PARTICIPANT_CONTEXT_TOO_LARGE");
306
+ for (const stream of selected) {
307
+ if (!stream.actor)
308
+ omissions.add("Some participants have no normalized recorded trace.");
309
+ for (const source of sourceEntries(bundle, stream)) {
310
+ if (evidence.length >= limits.evidence || textBytes >= limits.textBytes) {
311
+ omissions.add("Some evidence was omitted by the packet size limit.");
312
+ continue;
313
+ }
314
+ const text = boundedText(source.text, Math.min(16000, limits.textBytes - textBytes));
315
+ if (text !== source.text)
316
+ omissions.add("Some evidence text was truncated by the packet size limit.");
317
+ textBytes += Buffer.byteLength(text);
318
+ const id = `e${String(evidence.length + 1).padStart(6, "0")}`;
319
+ let capture = null;
320
+ if (source.capturePath !== null) {
321
+ if (images.length >= limits.captures)
322
+ omissions.add("Some captures were omitted by the capture count limit.");
323
+ else {
324
+ const bytes = await readBoundedStudyFile(prepared, source.capturePath, limits.imageBytes);
325
+ if (bytes === null || screenshotEvidenceError(source.capturePath, bytes) !== null) {
326
+ omissions.add("Some captures were missing, unsafe, oversized, or invalid PNG evidence.");
327
+ }
328
+ else if (imageBytes + bytes.length > limits.totalImageBytes) {
329
+ omissions.add("Some captures were omitted by the image byte limit.");
330
+ }
331
+ else {
332
+ imageBytes += bytes.length;
333
+ capture = { eventId: source.eventId, path: source.capturePath, sha256: sha256(bytes), mimeType: "image/png" };
334
+ images.push({ evidenceId: id, dataUrl: `data:image/png;base64,${bytes.toString("base64")}` });
335
+ }
336
+ }
337
+ }
338
+ else if (source.kind === "screenshot") {
339
+ omissions.add("Some screenshot references were absent or nonlocal.");
340
+ }
341
+ evidence.push({ id, streamId: stream.id, eventId: source.eventId, kind: source.kind, text,
342
+ quoteEligible: source.quoteEligible, at: source.at, elapsedMs: source.elapsedMs, frame: source.frame, capture });
343
+ }
344
+ }
345
+ const omittedStreamIds = bundle.streams.slice(limits.participants).map((stream) => stream.id);
346
+ const coverage = { includedStreamIds: selected.map((stream) => stream.id), omittedStreamIds,
347
+ evidenceCount: evidence.length, captureCount: images.length,
348
+ complete: omittedStreamIds.length === 0 && omissions.size === 0, omissions: [...omissions] };
349
+ const result = { runId: bundle.runId, sourceRunSha256: sha256(bundleBytes), inputDigest: "", participants, coverage, evidence, images };
350
+ result.inputDigest = digestStudyAnalysisInput(result);
351
+ validateStudyAnalysisInputMetadata(result);
352
+ const after = await readBoundedStudyFile(prepared, "run.json", limits.sourceBytes);
353
+ if (!after || !after.equals(bundleBytes))
354
+ throw new Error("ANALYSIS_SOURCE_CHANGED");
355
+ return result;
356
+ }
357
+ /** Validate exact source membership before any stored path may be read. */
358
+ export async function validateStudyAnalysisEvidence(prepared, artifact, bundleBytes) {
359
+ const bundle = parseSource(prepared, bundleBytes);
360
+ if (artifact.runId !== bundle.runId || artifact.sourceRunSha256 !== sha256(bundleBytes))
361
+ throw new Error("ANALYSIS_SOURCE_CHANGED");
362
+ const included = new Set(artifact.coverage.includedStreamIds);
363
+ const omitted = new Set(artifact.coverage.omittedStreamIds);
364
+ if (bundle.streams.some((stream) => !included.has(stream.id) && !omitted.has(stream.id))
365
+ || included.size + omitted.size !== bundle.streams.length)
366
+ throw new Error("ANALYSIS_SOURCE_COVERAGE_INVALID");
367
+ const sourceByStream = new Map(bundle.streams.map((stream) => [stream.id, sourceEntries(bundle, stream)]));
368
+ const context = new Map(artifact.participants.map((participant) => [participant.streamId, participant]));
369
+ if (context.size !== included.size || artifact.participants.length !== included.size)
370
+ throw new Error("ANALYSIS_PARTICIPANT_INPUT_INVALID");
371
+ for (const stream of bundle.streams.filter((candidate) => included.has(candidate.id))) {
372
+ const participant = context.get(stream.id);
373
+ if (!participant || hashStudyAnalysisValue(participant) !== hashStudyAnalysisValue(participantSource(stream))) {
374
+ throw new Error("ANALYSIS_PARTICIPANT_INPUT_INVALID");
375
+ }
376
+ }
377
+ const sourceKeys = new Set();
378
+ const checkedCaptures = new Map();
379
+ let checkedImageBytes = 0;
380
+ for (const entry of artifact.evidence) {
381
+ const matches = sourceByStream.get(entry.streamId)?.filter((source) => source.eventId === entry.eventId && source.kind === entry.kind) ?? [];
382
+ const source = matches[0];
383
+ const sourceKey = JSON.stringify([entry.streamId, entry.kind, entry.eventId]);
384
+ if (sourceKeys.has(sourceKey))
385
+ throw new Error("ANALYSIS_SOURCE_REFERENCE_DUPLICATE");
386
+ sourceKeys.add(sourceKey);
387
+ if (matches.length !== 1 || source === undefined || !source.text.startsWith(entry.text)
388
+ || entry.quoteEligible !== source.quoteEligible || entry.at !== source.at || entry.elapsedMs !== source.elapsedMs
389
+ || entry.frame !== source.frame)
390
+ throw new Error("ANALYSIS_SOURCE_REFERENCE_INVALID");
391
+ if (artifact.coverage.complete && (entry.text !== source.text || (source.capturePath !== null && entry.capture === null))) {
392
+ throw new Error("ANALYSIS_COVERAGE_INCOMPLETE");
393
+ }
394
+ if (entry.capture !== null) {
395
+ if (source.capturePath === null || entry.capture.path !== source.capturePath
396
+ || entry.capture.eventId !== source.eventId || entry.capture.mimeType !== "image/png")
397
+ throw new Error("ANALYSIS_CAPTURE_REFERENCE_INVALID");
398
+ let hash = checkedCaptures.get(source.capturePath);
399
+ if (hash === undefined) {
400
+ const bytes = await readBoundedStudyFile(prepared, source.capturePath, STUDY_EVIDENCE_LIMITS.imageBytes);
401
+ if (!bytes || screenshotEvidenceError(source.capturePath, bytes) !== null)
402
+ throw new Error("ANALYSIS_CAPTURE_UNAVAILABLE");
403
+ checkedImageBytes += bytes.length;
404
+ if (checkedImageBytes > STUDY_EVIDENCE_LIMITS.totalImageBytes)
405
+ throw new Error("ANALYSIS_IMAGE_LIMIT_EXCEEDED");
406
+ hash = sha256(bytes);
407
+ checkedCaptures.set(source.capturePath, hash);
408
+ }
409
+ if (hash !== entry.capture.sha256)
410
+ throw new Error("ANALYSIS_CAPTURE_CHANGED");
411
+ }
412
+ }
413
+ if (artifact.coverage.complete && [...sourceByStream.values()].reduce((total, entries) => total + entries.length, 0) !== artifact.evidence.length) {
414
+ throw new Error("ANALYSIS_COVERAGE_INCOMPLETE");
415
+ }
416
+ const current = await readBoundedStudyFile(prepared, "run.json", STUDY_EVIDENCE_LIMITS.sourceBytes);
417
+ if (!current?.equals(bundleBytes))
418
+ throw new Error("ANALYSIS_SOURCE_CHANGED");
419
+ }
420
+ //# sourceMappingURL=study-analysis-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"study-analysis-evidence.js","sourceRoot":"","sources":["../src/study-analysis-evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /** Deliberately separate from the stateful computer-use actor: one request, no tools or retries. */
2
+ export interface StudyAnalysisProviderRequest {
3
+ model: string;
4
+ instructions: string;
5
+ evidence: string;
6
+ images: {
7
+ evidenceId: string;
8
+ dataUrl: string;
9
+ }[];
10
+ schema: Record<string, unknown>;
11
+ maxOutputTokens: number;
12
+ timeoutMs: number;
13
+ signal?: AbortSignal;
14
+ }
15
+ export interface StudyAnalysisTokenUsage {
16
+ input: number;
17
+ output: number;
18
+ cachedInput?: number;
19
+ cacheWriteInput?: number;
20
+ }
21
+ export interface StudyAnalysisProviderResult {
22
+ status: "completed" | "incomplete" | "refused" | "failed" | "cancelled" | "timed_out";
23
+ /** Parsed output is still untrusted. The engine must validate its schema and evidence references. */
24
+ output: unknown;
25
+ usage: StudyAnalysisTokenUsage | null;
26
+ /** Dispatch does not imply a known charge. A failed request can still have consumed tokens. */
27
+ dispatched: boolean;
28
+ errorCode: "invalid_request" | "provider_http_error" | "provider_network_error" | "invalid_response" | "response_too_large" | "output_incomplete" | "refusal" | "cancelled" | "timeout" | null;
29
+ httpStatus?: number;
30
+ }
31
+ export type StudyAnalysisProvider = (request: StudyAnalysisProviderRequest) => Promise<StudyAnalysisProviderResult>;
32
+ /** Text and usage wire shapes reuse the captured closing-report contract; refusal fails closed. */
33
+ export declare function parseStudyAnalysisResponse(raw: unknown): StudyAnalysisProviderResult;
34
+ /** No alternate endpoint or env-derived base URL: evidence and credentials have one destination. */
35
+ export declare function createStudyAnalysisProvider(options: {
36
+ apiKey: string;
37
+ fetchFn?: typeof fetch;
38
+ }): StudyAnalysisProvider;
@@ -0,0 +1,140 @@
1
+ const MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
2
+ const MAX_REQUEST_BYTES = 32 * 1024 * 1024;
3
+ const INPUT_IMAGE = /^data:image\/(?:png|jpeg|webp);base64,[A-Za-z0-9+/]+={0,2}$/;
4
+ const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value)
5
+ ? value : {};
6
+ const count = (value) => Number.isSafeInteger(value) && value >= 0 && value <= 1e12;
7
+ function usageOf(raw) {
8
+ const usage = record(record(raw).usage);
9
+ const details = record(usage.input_tokens_details);
10
+ const input = usage.input_tokens;
11
+ const output = usage.output_tokens;
12
+ const cachedInput = details.cached_tokens;
13
+ const cacheWriteInput = details.cache_write_tokens;
14
+ if (!count(input) || !count(output)
15
+ || (cachedInput !== undefined && !count(cachedInput))
16
+ || (cacheWriteInput !== undefined && !count(cacheWriteInput))
17
+ || (cachedInput ?? 0) + (cacheWriteInput ?? 0) > input)
18
+ return null;
19
+ return { input, output,
20
+ ...(cachedInput === undefined ? {} : { cachedInput: cachedInput }),
21
+ ...(cacheWriteInput === undefined ? {} : { cacheWriteInput: cacheWriteInput }) };
22
+ }
23
+ /** Text and usage wire shapes reuse the captured closing-report contract; refusal fails closed. */
24
+ export function parseStudyAnalysisResponse(raw) {
25
+ const root = record(raw);
26
+ const usage = usageOf(raw);
27
+ const output = Array.isArray(root.output) ? root.output : [];
28
+ const contents = output.filter(item => record(item).type === "message")
29
+ .flatMap(item => Array.isArray(record(item).content) ? record(item).content : []);
30
+ const base = { output: null, usage, dispatched: true };
31
+ if (contents.some(item => record(item).type === "refusal")) {
32
+ return { ...base, status: "refused", errorCode: "refusal" };
33
+ }
34
+ if (root.status === "incomplete")
35
+ return { ...base, status: "incomplete", errorCode: "output_incomplete" };
36
+ if (root.status !== "completed" || output.some(item => !["message", "reasoning"].includes(String(record(item).type)))) {
37
+ return { ...base, status: "failed", errorCode: "invalid_response" };
38
+ }
39
+ // A single JSON answer is expected. Do not concatenate multiple answer objects or expose a
40
+ // refusal, reasoning item, or incomplete message as the report's prose.
41
+ const messages = output.filter(item => record(item).type === "message");
42
+ const texts = contents.filter(item => record(item).type === "output_text");
43
+ if (messages.length !== 1 || record(messages[0]).status !== "completed" || record(messages[0]).role !== "assistant" || texts.length !== 1
44
+ || contents.length !== 1 || typeof record(texts[0]).text !== "string") {
45
+ return { ...base, status: "failed", errorCode: "invalid_response" };
46
+ }
47
+ try {
48
+ return { ...base, status: "completed", output: JSON.parse(record(texts[0]).text), errorCode: null };
49
+ }
50
+ catch {
51
+ return { ...base, status: "failed", errorCode: "invalid_response" };
52
+ }
53
+ }
54
+ /** No alternate endpoint or env-derived base URL: evidence and credentials have one destination. */
55
+ export function createStudyAnalysisProvider(options) {
56
+ const fetchFn = options.fetchFn ?? fetch;
57
+ return async (request) => {
58
+ const failure = (errorCode, dispatched, status = "failed") => ({ status, output: null, usage: null, dispatched, errorCode });
59
+ if (request.signal?.aborted)
60
+ return failure("cancelled", false, "cancelled");
61
+ if (!options.apiKey.trim() || !/^[A-Za-z0-9_.-]{1,100}$/.test(request.model)
62
+ || !Number.isSafeInteger(request.maxOutputTokens) || request.maxOutputTokens < 256 || request.maxOutputTokens > 32_768
63
+ || !Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > 600_000
64
+ || request.images.length > 128 || request.images.some(image => !INPUT_IMAGE.test(image.dataUrl))) {
65
+ return failure("invalid_request", false);
66
+ }
67
+ const content = [
68
+ { type: "input_text", text: request.evidence },
69
+ ...request.images.flatMap(image => [
70
+ { type: "input_text", text: JSON.stringify({ captureEvidenceId: image.evidenceId }) },
71
+ { type: "input_image", image_url: image.dataUrl, detail: "high" }
72
+ ])
73
+ ];
74
+ const body = JSON.stringify({ model: request.model, instructions: request.instructions,
75
+ input: [{ role: "user", content }], store: false, tools: [], tool_choice: "none",
76
+ truncation: "disabled", service_tier: "default", reasoning: { effort: "high" }, max_output_tokens: request.maxOutputTokens,
77
+ text: { format: { type: "json_schema", name: "study_analysis", strict: true, schema: request.schema } } });
78
+ if (Buffer.byteLength(body) > MAX_REQUEST_BYTES)
79
+ return failure("invalid_request", false);
80
+ const controller = new AbortController();
81
+ let timedOut = false;
82
+ let dispatched = false;
83
+ const onAbort = () => controller.abort();
84
+ request.signal?.addEventListener("abort", onAbort, { once: true });
85
+ const timer = setTimeout(() => { timedOut = true; controller.abort(); }, request.timeoutMs);
86
+ try {
87
+ if (request.signal?.aborted)
88
+ return failure("cancelled", false, "cancelled");
89
+ dispatched = true;
90
+ const response = await fetchFn("https://api.openai.com/v1/responses", {
91
+ method: "POST", redirect: "error", signal: controller.signal,
92
+ headers: { Authorization: `Bearer ${options.apiKey}`, "Content-Type": "application/json" }, body
93
+ });
94
+ if (!response.ok) {
95
+ // Never read provider error prose: it may echo evidence or credentials.
96
+ await response.body?.cancel();
97
+ return { ...failure("provider_http_error", true), httpStatus: response.status };
98
+ }
99
+ if (!response.body)
100
+ return failure("invalid_response", true);
101
+ const reader = response.body.getReader();
102
+ const chunks = [];
103
+ let bytes = 0;
104
+ try {
105
+ while (true) {
106
+ const chunk = await reader.read();
107
+ if (chunk.done)
108
+ break;
109
+ bytes += chunk.value.byteLength;
110
+ if (bytes > MAX_RESPONSE_BYTES) {
111
+ await reader.cancel();
112
+ return failure("response_too_large", true);
113
+ }
114
+ chunks.push(chunk.value);
115
+ }
116
+ }
117
+ finally {
118
+ reader.releaseLock();
119
+ }
120
+ if (controller.signal.aborted)
121
+ return failure(timedOut ? "timeout" : "cancelled", true, timedOut ? "timed_out" : "cancelled");
122
+ try {
123
+ return parseStudyAnalysisResponse(JSON.parse(Buffer.concat(chunks).toString("utf8")));
124
+ }
125
+ catch {
126
+ return failure("invalid_response", true);
127
+ }
128
+ }
129
+ catch {
130
+ if (controller.signal.aborted)
131
+ return failure(timedOut ? "timeout" : "cancelled", dispatched, timedOut ? "timed_out" : "cancelled");
132
+ return failure("provider_network_error", dispatched);
133
+ }
134
+ finally {
135
+ clearTimeout(timer);
136
+ request.signal?.removeEventListener("abort", onAbort);
137
+ }
138
+ };
139
+ }
140
+ //# sourceMappingURL=study-analysis-provider.js.map