humanish 0.111.1 → 0.111.3
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/ARCHITECTURE.md +1 -1
- package/CHANGELOG.md +29 -0
- package/dist/cli/commands/study-route-computer-use.js +3 -8
- package/dist/cli/commands/study-route-preview.js +4 -6
- package/dist/cli/commands/study-route-shared-world.js +6 -7
- package/dist/evidence/redaction.d.ts +2 -2
- package/dist/evidence/redaction.js +3 -3
- package/dist/observer-app.html +6 -6
- package/dist/routes/computer-use/bundle-parts.d.ts +1 -32
- package/dist/routes/computer-use/bundle-parts.js +5 -92
- package/dist/routes/computer-use/e2b-desktop/prepare.js +11 -4
- package/dist/routes/computer-use/fanout-bundle.js +3 -2
- package/dist/routes/computer-use/live-phase.js +3 -7
- package/dist/routes/computer-use/participant-deps.d.ts +46 -0
- package/dist/routes/computer-use/participant-deps.js +48 -0
- package/dist/routes/computer-use/participant-facts.d.ts +5 -4
- package/dist/routes/computer-use/participant-facts.js +37 -2
- package/dist/routes/computer-use/participant-feedback.d.ts +33 -0
- package/dist/routes/computer-use/participant-feedback.js +92 -0
- package/dist/routes/computer-use/participant-model.d.ts +11 -0
- package/dist/routes/computer-use/participant-model.js +15 -0
- package/dist/routes/computer-use/preflight.js +33 -65
- package/dist/routes/computer-use/result.js +13 -52
- package/dist/routes/computer-use/route.js +6 -7
- package/dist/routes/computer-use/setup.d.ts +2 -6
- package/dist/routes/computer-use/setup.js +47 -93
- package/dist/routes/computer-use/single-bundle.js +3 -2
- package/dist/routes/computer-use/types.d.ts +2 -2
- package/dist/routes/preview.js +2 -8
- package/dist/routes/scripted/bundle.d.ts +2 -6
- package/dist/routes/scripted/result.d.ts +2 -1
- package/dist/routes/scripted/result.js +4 -4
- package/dist/routes/scripted/route.js +13 -38
- package/dist/routes/scripted/setup.d.ts +2 -1
- package/dist/routes/scripted/setup.js +21 -28
- package/dist/routes/scripted/subject.d.ts +3 -18
- package/dist/routes/scripted/subject.js +22 -78
- package/dist/routes/scripted/types.d.ts +2 -2
- package/dist/routes/shared-world/bundle.js +36 -1
- package/dist/routes/shared-world/comms.d.ts +2 -1
- package/dist/routes/shared-world/comms.js +3 -7
- package/dist/routes/shared-world/handoff.d.ts +2 -2
- package/dist/routes/shared-world/handoff.js +1 -1
- package/dist/routes/shared-world/participant-specs.d.ts +4 -5
- package/dist/routes/shared-world/participant-specs.js +19 -25
- package/dist/routes/shared-world/plan.js +11 -7
- package/dist/routes/shared-world/provisioned.d.ts +2 -1
- package/dist/routes/shared-world/provisioned.js +37 -80
- package/dist/routes/shared-world/result.js +17 -35
- package/dist/routes/shared-world/route.js +33 -36
- package/dist/routes/shared-world/setup.d.ts +2 -3
- package/dist/routes/shared-world/setup.js +11 -29
- package/dist/routes/shared-world/types.d.ts +6 -15
- package/dist/routes/terminal/dry-run.js +14 -24
- package/dist/routes/terminal/live-finish.d.ts +0 -1
- package/dist/routes/terminal/live-finish.js +2 -2
- package/dist/routes/terminal/route.js +9 -15
- package/dist/routes/terminal/session.d.ts +2 -3
- package/dist/routes/terminal/session.js +28 -40
- package/dist/routes/terminal/trace.d.ts +1 -1
- package/dist/routes/terminal/types.d.ts +2 -2
- package/dist/run/run.d.ts +55 -1
- package/dist/run/run.js +38 -2
- package/dist/run/secrets.d.ts +22 -0
- package/dist/run/secrets.js +33 -0
- package/dist/run/study-result.d.ts +34 -0
- package/dist/run/study-result.js +16 -0
- package/dist/study/requirements.d.ts +60 -5
- package/dist/study/requirements.js +88 -2
- package/dist/study/run-study-events.d.ts +4 -3
- package/dist/study/run-study-events.js +9 -14
- package/dist/study/run-study-options.d.ts +4 -1
- package/dist/study/run-study-options.js +22 -32
- package/dist/substrates/e2b/subject-sandbox.d.ts +58 -0
- package/dist/substrates/e2b/subject-sandbox.js +94 -0
- package/docs/contracts/core.md +5 -4
- package/docs/contracts/feedback.md +12 -5
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// The subject sandbox of a provisioned clone: the one E2B desktop that serves the app, on the
|
|
2
|
+
// scripted clone route and the shared-world provisioned plane. Both routes create, measure and
|
|
3
|
+
// release it through this class, so a change to its request, its size check or its release
|
|
4
|
+
// reading is one edit. What runs inside the sandbox (the caller's prepare hook, provisioning,
|
|
5
|
+
// getHost) stays with each route.
|
|
6
|
+
import { redactText } from "../../evidence/redaction.js";
|
|
7
|
+
import { DEFAULT_STATE_STEP_TIMEOUT_MS } from "../../subject/state.js";
|
|
8
|
+
import { observeDesktopResources } from "./desktop-resources.js";
|
|
9
|
+
import { SANDBOX_TIMEOUT_BUFFER_MS, SUBJECT_PROVISION_BUDGET_MS } from "./lifetime.js";
|
|
10
|
+
import { acquireE2BDesktopSandbox, readE2BRelease } from "./sandbox.js";
|
|
11
|
+
export class E2BSubjectSandbox {
|
|
12
|
+
sandboxId;
|
|
13
|
+
killed = false;
|
|
14
|
+
/** The scrubbed release warning when the release is unconfirmed. */
|
|
15
|
+
releaseWarning;
|
|
16
|
+
run;
|
|
17
|
+
allocation;
|
|
18
|
+
createdAtMs;
|
|
19
|
+
tornDownAtMs;
|
|
20
|
+
resources;
|
|
21
|
+
constructor(run) {
|
|
22
|
+
this.run = run;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates the sandbox and reads its size. The receipt is on disk before this returns, so
|
|
26
|
+
* `humanish reclaim` can kill the sandbox by exact id if the process dies during provisioning.
|
|
27
|
+
*/
|
|
28
|
+
async acquire(request) {
|
|
29
|
+
const { envs } = request;
|
|
30
|
+
const { warnings, scrub } = this.run;
|
|
31
|
+
const timeoutMs = request.sessionTimeoutMs +
|
|
32
|
+
SUBJECT_PROVISION_BUDGET_MS +
|
|
33
|
+
request.seed.reduce((sum, step) => sum + (step.timeoutMs ?? DEFAULT_STATE_STEP_TIMEOUT_MS), 0) +
|
|
34
|
+
SANDBOX_TIMEOUT_BUFFER_MS;
|
|
35
|
+
const subject = await acquireE2BDesktopSandbox({
|
|
36
|
+
module: request.module,
|
|
37
|
+
options: {
|
|
38
|
+
apiKey: request.apiKey,
|
|
39
|
+
requestTimeoutMs: request.requestTimeoutMs,
|
|
40
|
+
timeoutMs,
|
|
41
|
+
metadata: request.metadata,
|
|
42
|
+
...(Object.keys(envs).length > 0 ? { envs } : {}),
|
|
43
|
+
dpi: 96,
|
|
44
|
+
lifecycle: { onTimeout: "kill" },
|
|
45
|
+
},
|
|
46
|
+
template: request.template,
|
|
47
|
+
retry: {
|
|
48
|
+
// A failed first attempt may have allocated a sandbox whose id never reached this run;
|
|
49
|
+
// its own kill-on-timeout reclaims it.
|
|
50
|
+
onRetry: (reason) => {
|
|
51
|
+
warnings.push(`Subject sandbox create retried once after a transient provider error (${redactText(scrub(reason))}). A sandbox the failed attempt may have allocated is reclaimed by its ${timeoutMs} ms timeout.`);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
receipt: { root: request.root, participantId: "subject" },
|
|
55
|
+
});
|
|
56
|
+
this.allocation = subject.allocation;
|
|
57
|
+
this.sandboxId = subject.allocation.resourceId;
|
|
58
|
+
this.createdAtMs = this.run.now();
|
|
59
|
+
const resources = await observeDesktopResources(subject.sandbox);
|
|
60
|
+
this.resources = resources;
|
|
61
|
+
if ("reason" in resources)
|
|
62
|
+
warnings.push(`Subject sandbox resource size unavailable (${resources.reason}); its compute cost remains unpriced.`);
|
|
63
|
+
return subject.sandbox;
|
|
64
|
+
}
|
|
65
|
+
/** Releases the sandbox by exact id, when one was acquired. An unconfirmed release is reported. */
|
|
66
|
+
async release() {
|
|
67
|
+
const { warnings, scrub, now } = this.run;
|
|
68
|
+
if (this.allocation === undefined)
|
|
69
|
+
return;
|
|
70
|
+
const released = await this.allocation.close();
|
|
71
|
+
const reading = readE2BRelease(released, { label: "Subject sandbox", scrub, costSpan: true });
|
|
72
|
+
this.killed = reading.released;
|
|
73
|
+
if (reading.warning)
|
|
74
|
+
warnings.push(reading.warning);
|
|
75
|
+
if (!reading.released)
|
|
76
|
+
this.releaseWarning = reading.warning ?? "Subject sandbox release is unconfirmed.";
|
|
77
|
+
// Without a kill method, or in E2B debug mode, no kill reached E2B, so there is no teardown
|
|
78
|
+
// time to record.
|
|
79
|
+
if (released.status !== "unconfirmed" || released.reason !== "release_unavailable")
|
|
80
|
+
this.tornDownAtMs = now();
|
|
81
|
+
}
|
|
82
|
+
/** The billed span and size, when a sandbox was acquired. */
|
|
83
|
+
desktopUsage() {
|
|
84
|
+
if (this.sandboxId === undefined)
|
|
85
|
+
return undefined;
|
|
86
|
+
return {
|
|
87
|
+
durationMs: this.createdAtMs === undefined || this.tornDownAtMs === undefined
|
|
88
|
+
? undefined
|
|
89
|
+
: Math.max(0, this.tornDownAtMs - this.createdAtMs),
|
|
90
|
+
observation: this.resources,
|
|
91
|
+
killed: this.killed,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
package/docs/contracts/core.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Core Contract
|
|
2
2
|
|
|
3
|
-
Each route
|
|
4
|
-
|
|
5
|
-
`.humanish/runs/<id
|
|
6
|
-
|
|
3
|
+
Each route builds its bundle and starts the run through the run scope in
|
|
4
|
+
`src/run/run.ts`. `startRun` takes the caller's run id or mints one from the
|
|
5
|
+
route's prefix, creates `.humanish/runs/<id>`, begins `status.json` and captures
|
|
6
|
+
the run's source; preview mints its own id and builds its source first. The
|
|
7
|
+
`Run` it returns publishes `run.json`, its projections and the latest pointer. `src/run/paths.ts` holds the
|
|
7
8
|
shared path rules and `src/run/git-state.ts` captures git state. The table
|
|
8
9
|
below lists the records current bundles write.
|
|
9
10
|
|
|
@@ -50,16 +50,23 @@ humanish feedback issue-url --run latest --repo owner/repo
|
|
|
50
50
|
### `list`
|
|
51
51
|
|
|
52
52
|
Reads feedback candidates from the run bundle. Does not mutate. Candidates come
|
|
53
|
-
from the computer-use
|
|
54
|
-
study goal, and from an adapter's `deriveFeedback` hook.
|
|
53
|
+
from the computer-use and shared-world routes, when a participant reports
|
|
54
|
+
friction or abandons the study goal, and from an adapter's `deriveFeedback` hook.
|
|
55
|
+
Both routes build them with `participantFeedbackCandidates`
|
|
56
|
+
(`src/routes/computer-use/participant-feedback.ts`): one candidate per reporting
|
|
57
|
+
participant, named by its participant id, with that participant's own
|
|
58
|
+
instructions as `expected` and no merging of reports that match.
|
|
59
|
+
A shared-world candidate also cites the run's comms thread when the study
|
|
60
|
+
captured one, since that thread belongs to the shared app. Adapter candidates
|
|
61
|
+
follow the participant candidates.
|
|
55
62
|
|
|
56
63
|
The list also shows any saved draft. An empty `candidates` array means no usable
|
|
57
64
|
candidate was recorded; it does not mean a run-summary draft is unavailable.
|
|
58
65
|
Listing does not create a draft or check public-sharing eligibility.
|
|
59
66
|
|
|
60
|
-
For completed computer-use sessions, participant-reported
|
|
61
|
-
the redacted closing report, a completed debrief's
|
|
62
|
-
observed-report clauses in earlier messages.
|
|
67
|
+
For completed computer-use and shared-world sessions, participant-reported
|
|
68
|
+
friction comes from the redacted closing report, a completed debrief's
|
|
69
|
+
`frictionReports`, and observed-report clauses in earlier messages.
|
|
63
70
|
Matching `stopWhen` or ending a dwell window does not discard an earlier
|
|
64
71
|
report or change the successful completion verdict. Exact repeated reports
|
|
65
72
|
appear once in the participant's candidate. Harness notices, reasoning, and observed
|