humanish 0.110.4 → 0.111.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/CHANGELOG.md +31 -0
- package/CONTEXT.md +2 -2
- package/dist/actors/codex/restricted-participant-policy.d.ts +2 -0
- package/dist/actors/codex/restricted-participant-policy.js +30 -2
- package/dist/actors/codex/restricted-participant.js +1 -1
- package/dist/actors/computer-use/executor-diagnostic.d.ts +15 -0
- package/dist/actors/computer-use/executor-diagnostic.js +105 -0
- package/dist/actors/computer-use/executor-error.d.ts +18 -3
- package/dist/actors/computer-use/executor-error.js +30 -4
- package/dist/actors/computer-use/loop/actions.d.ts +6 -3
- package/dist/actors/computer-use/loop/actions.js +27 -7
- package/dist/actors/computer-use/loop/ending.js +9 -1
- package/dist/actors/computer-use/loop/types.d.ts +14 -0
- package/dist/actors/computer-use/loop.d.ts +1 -1
- package/dist/actors/computer-use/loop.js +1 -1
- package/dist/actors/computer-use/openai-context.d.ts +8 -2
- package/dist/actors/computer-use/openai-context.js +91 -26
- package/dist/actors/computer-use/openai-provider.js +55 -12
- package/dist/actors/computer-use/openai-requests.d.ts +2 -1
- package/dist/actors/computer-use/openai-requests.js +4 -1
- package/dist/actors/contract.d.ts +7 -1
- package/dist/actors/local-agent/claude-session.js +1 -1
- package/dist/actors/local-agent/cli.js +1 -1
- package/dist/actors/scripted-browser/actor.d.ts +2 -2
- package/dist/browser-control/client.js +5 -5
- package/dist/browser-control/protocol.d.ts +30 -1
- package/dist/browser-control/protocol.js +19 -2
- package/dist/browser-control/transport.d.ts +3 -2
- package/dist/browser-control/transport.js +12 -7
- package/dist/cli/commands/study-route-computer-use.js +2 -2
- package/dist/cli/commands/study-route-shared-world.js +2 -2
- package/dist/cli/commands/study.js +1 -4
- package/dist/cli/doctor.js +11 -0
- package/dist/evidence/encoded-text.d.ts +3 -3
- package/dist/evidence/encoded-text.js +10 -5
- package/dist/evidence/redaction.d.ts +2 -2
- package/dist/evidence/redaction.js +18 -7
- package/dist/guest/browser-tools.js +5 -1
- package/dist/guest/chromium-text.js +42 -18
- package/dist/guest/desktop-executor.js +5 -1
- package/dist/keys/key-resolution.d.ts +3 -0
- package/dist/keys/key-resolution.js +15 -2
- package/dist/routes/computer-use/bundle-parts.d.ts +4 -0
- package/dist/routes/computer-use/bundle-parts.js +7 -2
- package/dist/routes/computer-use/fanout-bundle.js +4 -2
- package/dist/routes/computer-use/local-vm.js +1 -2
- package/dist/routes/computer-use/participant-model.js +7 -2
- package/dist/routes/computer-use/plan.js +7 -10
- package/dist/routes/computer-use/preflight.js +1 -1
- package/dist/routes/computer-use/result.js +1 -1
- package/dist/routes/computer-use/route.js +2 -3
- package/dist/routes/computer-use/setup.js +2 -2
- package/dist/routes/computer-use/types.d.ts +4 -4
- package/dist/routes/preview.js +1 -0
- package/dist/routes/scripted/plan.js +4 -5
- package/dist/routes/scripted/route.js +3 -3
- package/dist/routes/scripted/scenario.d.ts +1 -1
- package/dist/routes/scripted/scenario.js +3 -3
- package/dist/routes/scripted/types.d.ts +2 -2
- package/dist/routes/shared-world/handoff.js +1 -1
- package/dist/routes/shared-world/participant-specs.js +1 -1
- package/dist/routes/shared-world/plan.js +6 -8
- package/dist/routes/shared-world/route.js +2 -2
- package/dist/routes/shared-world/setup.js +1 -0
- package/dist/routes/shared-world/types.d.ts +1 -1
- package/dist/routes/terminal/bundle.d.ts +3 -3
- package/dist/routes/terminal/dry-run.js +1 -0
- package/dist/routes/terminal/ledger.d.ts +2 -2
- package/dist/routes/terminal/lifetime.js +1 -1
- package/dist/routes/terminal/live-finish.js +25 -6
- package/dist/routes/terminal/live-sandbox.js +5 -1
- package/dist/routes/terminal/plan.js +3 -4
- package/dist/routes/terminal/recorder.d.ts +6 -0
- package/dist/routes/terminal/recorder.js +61 -6
- package/dist/routes/terminal/route.js +2 -3
- package/dist/routes/terminal/session.js +2 -1
- package/dist/routes/terminal/token-usage.d.ts +3 -0
- package/dist/routes/terminal/token-usage.js +5 -0
- package/dist/routes/terminal/types.d.ts +3 -2
- package/dist/routes/terminal/types.js +2 -1
- package/dist/run/dry-run.js +1 -0
- package/dist/run/results.d.ts +3 -1
- package/dist/run/run.d.ts +2 -0
- package/dist/run/run.js +16 -2
- package/dist/run/terminal-contract.d.ts +10 -0
- package/dist/run/terminal-contract.js +27 -9
- package/dist/run-study.d.ts +5 -3
- package/dist/run-study.js +7 -11
- package/dist/study/adapter-scorer-loader.d.ts +1 -1
- package/dist/study/adapter-scorer-loader.js +3 -3
- package/dist/study/composition-rules.js +36 -27
- package/dist/study/config.d.ts +29 -13
- package/dist/study/config.js +174 -157
- package/dist/study/discover.d.ts +1 -1
- package/dist/study/discover.js +1 -1
- package/dist/study/doctor.js +4 -5
- package/dist/study/keys.d.ts +250 -2
- package/dist/study/keys.js +32 -62
- package/dist/study/migrate/convert.js +3 -4
- package/dist/study/migrate/v2.d.ts +22 -7
- package/dist/study/migrate/v2.js +173 -23
- package/dist/study/parse/actors.d.ts +11 -32
- package/dist/study/parse/actors.js +11 -156
- package/dist/study/parse/comms.js +6 -2
- package/dist/study/parse/execution.d.ts +9 -4
- package/dist/study/parse/execution.js +4 -39
- package/dist/study/parse/{study-v3.d.ts → front.d.ts} +6 -17
- package/dist/study/parse/{study-v3.js → front.js} +24 -112
- package/dist/study/parse/subject.d.ts +2 -0
- package/dist/study/parse/subject.js +15 -18
- package/dist/study/parse/url-credentials.d.ts +3 -3
- package/dist/study/parse/url-credentials.js +155 -13
- package/dist/study/persona-resolve.js +7 -9
- package/dist/study/plan-base.d.ts +1 -1
- package/dist/study/plan-base.js +5 -7
- package/dist/study/plan-participants.d.ts +2 -2
- package/dist/study/plan-participants.js +3 -3
- package/dist/study/plan-types.d.ts +7 -5
- package/dist/study/plan.js +12 -6
- package/dist/study/preflight-probes.js +2 -2
- package/dist/study/preflight.d.ts +1 -1
- package/dist/study/preflight.js +1 -1
- package/dist/study/routing.d.ts +5 -5
- package/dist/study/routing.js +16 -16
- package/dist/study/run-study-options.d.ts +1 -1
- package/dist/study/run-study-options.js +2 -2
- package/dist/study/study-deps.d.ts +1 -1
- package/dist/study/study-fields.d.ts +4 -25
- package/dist/study/study-fields.js +15 -44
- package/dist/study/summary.js +13 -8
- package/dist/study/types.d.ts +51 -128
- package/dist/study/types.js +0 -1
- package/dist/study/url-credentials.js +3 -4
- package/dist/study/validation.d.ts +2 -10
- package/dist/study/validation.js +23 -53
- package/dist/study/warnings.d.ts +11 -3
- package/dist/study/warnings.js +56 -110
- package/dist/substrates/local/runtime-config.js +11 -13
- package/docs/architecture/browser-control.md +12 -2
- package/docs/architecture/guest-desktop.md +7 -1
- package/docs/architecture/terminal-product-route.md +3 -2
- package/docs/contracts/schemas.md +39 -9
- package/package.json +1 -1
- package/dist/study/parse/study.d.ts +0 -38
- package/dist/study/parse/study.js +0 -225
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
// humanish.study.v3, parsed into a config with the file's own keys (StudyV3). parseStudy still
|
|
2
|
-
// rewrites a v3 file into the v2 spelling and parses that (parse/study-v3.ts).
|
|
3
|
-
// tests/study/parse-differential.test.ts holds the two to the same result. The checks that read
|
|
4
|
-
// more than one section still take the v2 shape, so they run on toLegacy's view of the study.
|
|
5
|
-
import { isRecord } from "../../run/type-guards.js";
|
|
6
|
-
import { checkStudyConfig } from "../config.js";
|
|
7
|
-
import { routeOf } from "../routing.js";
|
|
8
|
-
import { ID_PATTERN, STUDY_SCHEMA, V2_SCHEMA, } from "../types.js";
|
|
9
|
-
import { inertFieldLabels, inertFieldPaths } from "../warnings.js";
|
|
10
|
-
import { parseActorFields, parseActorType, parseParticipantEntries, withoutParticipants, withParticipants, } from "./actors.js";
|
|
11
|
-
import { parseComms } from "./comms.js";
|
|
12
|
-
import { parseDefaults, parseExecution, parsePolicies, parseReview } from "./execution.js";
|
|
13
|
-
import { readStudyFront, studySpelling } from "./study-v3.js";
|
|
14
|
-
import { parseSubject } from "./subject.js";
|
|
15
|
-
import { invalid, nonNegNumber, optionalStr, str } from "./values.js";
|
|
16
|
-
/**
|
|
17
|
-
* Validate a parsed humanish.study.v3 document into a StudyV3, with the messages parseStudy gives.
|
|
18
|
-
* Pure: the caller owns file IO. parseStudy refuses a humanish.lab.v2 document before this runs.
|
|
19
|
-
*/
|
|
20
|
-
export function parseStudyV3(raw, options = {}) {
|
|
21
|
-
if (!isRecord(raw))
|
|
22
|
-
return invalid("A study file must be a YAML object.");
|
|
23
|
-
if (raw.schema !== STUDY_SCHEMA) {
|
|
24
|
-
return invalid(`The study schema must be ${STUDY_SCHEMA} or ${V2_SCHEMA}.`);
|
|
25
|
-
}
|
|
26
|
-
const front = readStudyFront(raw, options.inert === "report");
|
|
27
|
-
if (!front.ok)
|
|
28
|
-
return front;
|
|
29
|
-
const study = parseSections(raw, front.value);
|
|
30
|
-
if (!study.ok)
|
|
31
|
-
return study;
|
|
32
|
-
const spell = (message) => options.inert === "report"
|
|
33
|
-
? message
|
|
34
|
-
: studySpelling(message, front.value.route, front.value.participants.source);
|
|
35
|
-
const checked = checkStudyConfig(toLegacy(study.value));
|
|
36
|
-
if (!checked.ok)
|
|
37
|
-
return invalid(spell(checked.error.message));
|
|
38
|
-
const { route } = study.value;
|
|
39
|
-
const taken = routeOf(checked.config);
|
|
40
|
-
if (taken !== route) {
|
|
41
|
-
return invalid(`This study declares route: ${route}, but its subject (source: ${checked.config.subject.source}) and actor (type: ${checked.config.actors[0]?.type}) take the ${taken} route. Change \`route\`, or change the subject or actor.`);
|
|
42
|
-
}
|
|
43
|
-
const config = withFilledDefaults(study.value, checked.config);
|
|
44
|
-
const warnings = checked.warnings.map(spell);
|
|
45
|
-
if (options.inert === "report") {
|
|
46
|
-
return { ok: true, config, warnings, inert: inertFieldPaths(checked.config) };
|
|
47
|
-
}
|
|
48
|
-
const inert = inertFieldLabels(checked.config);
|
|
49
|
-
if (inert.length > 0) {
|
|
50
|
-
return invalid(spell(`route: ${route} does not read ${inert.join(", ")}. Remove ${inert.length === 1 ? "it" : "them"}.`));
|
|
51
|
-
}
|
|
52
|
-
return { ok: true, config, warnings };
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* A v3 study in the v2 spelling: the actor holds its participants, `caps` moves under `execution`
|
|
56
|
-
* or `scenario`, and a shared world is `subject.topology: shared-world`. The checks that read more
|
|
57
|
-
* than one section run on this view until StudyConfig has the v3 shape.
|
|
58
|
-
*/
|
|
59
|
-
export function toLegacy(study) {
|
|
60
|
-
const { route, participants, caps } = study;
|
|
61
|
-
const group = typeof participants === "object" && !Array.isArray(participants) ? participants : undefined;
|
|
62
|
-
const actor = withParticipants(study.actor, {
|
|
63
|
-
count: typeof participants === "number" ? participants : (group?.count ?? study.surfaces?.length),
|
|
64
|
-
entries: Array.isArray(participants) ? participants : undefined,
|
|
65
|
-
instruction: group?.instruction,
|
|
66
|
-
});
|
|
67
|
-
const { source, ...subject } = study.subject;
|
|
68
|
-
const execution = caps !== undefined && route !== "terminal" ? { ...study.execution, caps } : study.execution;
|
|
69
|
-
const scenario = {
|
|
70
|
-
...(study.scenario === undefined ? {} : { ref: study.scenario }),
|
|
71
|
-
...(study.mode === undefined ? {} : { mode: study.mode }),
|
|
72
|
-
...(caps !== undefined && route === "terminal" ? { caps } : {}),
|
|
73
|
-
};
|
|
74
|
-
return {
|
|
75
|
-
schema: study.schema,
|
|
76
|
-
id: study.id,
|
|
77
|
-
...(study.title === undefined ? {} : { title: study.title }),
|
|
78
|
-
...(study.description === undefined ? {} : { description: study.description }),
|
|
79
|
-
subject: route === "shared-world" ? { source, topology: "shared-world", ...subject } : study.subject,
|
|
80
|
-
actors: [actor],
|
|
81
|
-
...(execution === undefined ? {} : { execution }),
|
|
82
|
-
...(Object.keys(scenario).length > 0 ? { scenario } : {}),
|
|
83
|
-
...(study.policies === undefined ? {} : { policies: study.policies }),
|
|
84
|
-
...(study.review === undefined ? {} : { review: study.review }),
|
|
85
|
-
...(study.defaults === undefined ? {} : { defaults: study.defaults }),
|
|
86
|
-
...(study.comms === undefined ? {} : { comms: study.comms }),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
// Each section in the order the v2 parser reads it, so a file with more than one error reports the
|
|
90
|
-
// same one first.
|
|
91
|
-
function parseSections(raw, front) {
|
|
92
|
-
const id = str(raw.id);
|
|
93
|
-
if (!id || !ID_PATTERN.test(id)) {
|
|
94
|
-
return invalid("The study id must be a public-safe token starting with a letter or digit (/^[A-Za-z0-9][A-Za-z0-9_.-]*$/).");
|
|
95
|
-
}
|
|
96
|
-
const subject = parseSubject(raw.subject);
|
|
97
|
-
if (!subject.ok)
|
|
98
|
-
return subject;
|
|
99
|
-
const type = parseActorType(front.actor, "actor");
|
|
100
|
-
if (!type.ok)
|
|
101
|
-
return type;
|
|
102
|
-
const participants = parseParticipants(raw.participants, front.participants);
|
|
103
|
-
if (!participants.ok)
|
|
104
|
-
return participants;
|
|
105
|
-
const fields = parseActorFields(front.actor, "actor");
|
|
106
|
-
if (!fields.ok)
|
|
107
|
-
return fields;
|
|
108
|
-
const execution = parseExecution(raw.execution);
|
|
109
|
-
if (!execution.ok)
|
|
110
|
-
return execution;
|
|
111
|
-
const caps = parseCaps(raw.caps);
|
|
112
|
-
if (!caps.ok)
|
|
113
|
-
return caps;
|
|
114
|
-
if (isRecord(raw.policies) &&
|
|
115
|
-
raw.policies.mediaPermission !== undefined &&
|
|
116
|
-
raw.policies.mediaPermission !== "prompt" &&
|
|
117
|
-
raw.policies.mediaPermission !== "granted") {
|
|
118
|
-
return invalid("`policies.mediaPermission` must be `prompt` (the participant answers the browser's own dialog) or `granted`.");
|
|
119
|
-
}
|
|
120
|
-
const policies = parsePolicies(raw.policies);
|
|
121
|
-
if (!policies.ok)
|
|
122
|
-
return policies;
|
|
123
|
-
const review = parseReview(raw.review);
|
|
124
|
-
if (!review.ok)
|
|
125
|
-
return review;
|
|
126
|
-
if (isRecord(raw.defaults) && raw.defaults.open !== undefined) {
|
|
127
|
-
if (typeof raw.defaults.open !== "boolean")
|
|
128
|
-
return invalid("`defaults.open` must be true or false.");
|
|
129
|
-
}
|
|
130
|
-
const defaults = parseDefaults(raw.defaults);
|
|
131
|
-
const comms = parseComms(raw.comms);
|
|
132
|
-
if (!comms.ok)
|
|
133
|
-
return comms;
|
|
134
|
-
const mode = raw.mode === "dry-run" || raw.mode === "live" ? raw.mode : undefined;
|
|
135
|
-
const surfaces = front.surfaces === 2
|
|
136
|
-
? ["desktop", "mobile"]
|
|
137
|
-
: front.surfaces === 1
|
|
138
|
-
? ["desktop"]
|
|
139
|
-
: undefined;
|
|
140
|
-
const scenario = str(raw.scenario);
|
|
141
|
-
return {
|
|
142
|
-
ok: true,
|
|
143
|
-
value: {
|
|
144
|
-
schema: STUDY_SCHEMA,
|
|
145
|
-
id,
|
|
146
|
-
...optionalStr("title", raw.title),
|
|
147
|
-
...optionalStr("description", raw.description),
|
|
148
|
-
route: front.route,
|
|
149
|
-
...(mode === undefined ? {} : { mode }),
|
|
150
|
-
subject: subject.value,
|
|
151
|
-
actor: { type: type.value, ...fields.value },
|
|
152
|
-
...(participants.value === undefined ? {} : { participants: participants.value }),
|
|
153
|
-
...(surfaces === undefined ? {} : { surfaces }),
|
|
154
|
-
...(caps.value === undefined ? {} : { caps: caps.value }),
|
|
155
|
-
...(execution.value === undefined ? {} : { execution: execution.value }),
|
|
156
|
-
...(scenario === undefined ? {} : { scenario }),
|
|
157
|
-
...(policies.value === undefined ? {} : { policies: policies.value }),
|
|
158
|
-
...(review.value === undefined ? {} : { review: review.value }),
|
|
159
|
-
...(defaults === undefined ? {} : { defaults }),
|
|
160
|
-
...(comms.value === undefined ? {} : { comms: comms.value }),
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
// `participants` in the form the file wrote it. readStudyFront has checked the form against the
|
|
165
|
-
// route and expanded each list entry that has a count; the entries parse here, each named by the
|
|
166
|
-
// `participants` entry it came from. An instruction that is not a non-empty string is dropped, as
|
|
167
|
-
// the v2 parser drops it.
|
|
168
|
-
function parseParticipants(raw, read) {
|
|
169
|
-
if (read.entries !== undefined) {
|
|
170
|
-
const { source } = read;
|
|
171
|
-
return parseParticipantEntries(read.entries, {
|
|
172
|
-
list: "participants",
|
|
173
|
-
entry: (index) => `participants[${source[index] ?? index}]`,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
if (typeof raw === "number")
|
|
177
|
-
return { ok: true, value: read.count };
|
|
178
|
-
if (!isRecord(raw))
|
|
179
|
-
return { ok: true, value: undefined };
|
|
180
|
-
const instruction = str(read.instruction);
|
|
181
|
-
return {
|
|
182
|
-
ok: true,
|
|
183
|
-
value: {
|
|
184
|
-
...(read.count === undefined ? {} : { count: read.count }),
|
|
185
|
-
...(instruction === undefined ? {} : { instruction }),
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* A caps block's values. A value that is not a non-negative number refuses the study: a cap that
|
|
191
|
-
* does nothing must not look like one that holds. readStudyFront has checked the keys against the
|
|
192
|
-
* route; migrate checks a v2 file's two blocks with it.
|
|
193
|
-
*/
|
|
194
|
-
export function parseCaps(raw) {
|
|
195
|
-
if (raw === undefined)
|
|
196
|
-
return { ok: true, value: undefined };
|
|
197
|
-
if (!isRecord(raw)) {
|
|
198
|
-
return invalid("`caps` must be an object ({ maxUsd?, maxTotalUsd?, maxJobs?, maxMinutes? }).");
|
|
199
|
-
}
|
|
200
|
-
const caps = {};
|
|
201
|
-
for (const key of ["maxUsd", "maxTotalUsd", "maxJobs", "maxMinutes"]) {
|
|
202
|
-
if (raw[key] === undefined)
|
|
203
|
-
continue;
|
|
204
|
-
const value = nonNegNumber(raw[key]);
|
|
205
|
-
if (value === undefined)
|
|
206
|
-
return invalid(`\`caps.${key}\` must be a non-negative number.`);
|
|
207
|
-
caps[key] = value;
|
|
208
|
-
}
|
|
209
|
-
return { ok: true, value: Object.keys(caps).length > 0 ? caps : undefined };
|
|
210
|
-
}
|
|
211
|
-
// checkStudyConfig fills defaults in the v2 view: a shared world's `execution.concurrency`,
|
|
212
|
-
// `comms.email.recipients`, and the local browser's actor model and effort, execution timeout and
|
|
213
|
-
// resolution and `review.analysis`. Each has the same path in both shapes, so it is copied back.
|
|
214
|
-
function withFilledDefaults(study, checked) {
|
|
215
|
-
const [actor] = checked.actors;
|
|
216
|
-
const execution = { ...checked.execution };
|
|
217
|
-
delete execution.caps;
|
|
218
|
-
return {
|
|
219
|
-
...study,
|
|
220
|
-
actor: actor === undefined ? study.actor : withoutParticipants(actor),
|
|
221
|
-
...(Object.keys(execution).length > 0 ? { execution } : {}),
|
|
222
|
-
...(checked.review === undefined ? {} : { review: checked.review }),
|
|
223
|
-
...(checked.comms === undefined ? {} : { comms: checked.comms }),
|
|
224
|
-
};
|
|
225
|
-
}
|