humanish 0.110.2 → 0.110.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 +10 -15
- package/CHANGELOG.md +13 -0
- package/CONTEXT.md +1 -1
- package/dist/actors/computer-use/actor.js +2 -2
- package/dist/actors/computer-use/loop/ending.js +1 -1
- package/dist/actors/registry.js +1 -1
- package/dist/analysis/automatic-completion.js +8 -0
- package/dist/cli/commands/observe.js +3 -2
- package/dist/cli/commands/study-run.js +9 -19
- package/dist/cli/findings.d.ts +5 -0
- package/dist/cli/findings.js +21 -0
- package/dist/cli/io.d.ts +2 -1
- package/dist/cli/io.js +3 -2
- package/dist/cli/observer-follow.d.ts +6 -2
- package/dist/cli/observer-follow.js +15 -5
- package/dist/evidence/redaction.js +15 -4
- package/dist/routes/computer-use/participant-runs.d.ts +6 -9
- package/dist/routes/computer-use/participant-runs.js +16 -36
- package/dist/routes/computer-use/plan.d.ts +2 -2
- package/dist/routes/computer-use/plan.js +1 -1
- package/dist/routes/computer-use/route.d.ts +5 -18
- package/dist/routes/computer-use/route.js +17 -78
- package/dist/routes/computer-use/setup.d.ts +3 -2
- package/dist/routes/computer-use/types.d.ts +6 -10
- package/dist/routes/scripted/route.d.ts +4 -17
- package/dist/routes/scripted/route.js +10 -42
- package/dist/routes/scripted/types.d.ts +1 -6
- package/dist/routes/shared-world/route.d.ts +5 -11
- package/dist/routes/shared-world/route.js +24 -63
- package/dist/routes/shared-world/types.d.ts +2 -6
- package/dist/routes/terminal/route.d.ts +3 -13
- package/dist/routes/terminal/route.js +19 -59
- package/dist/routes/terminal/session.d.ts +2 -3
- package/dist/routes/terminal/session.js +2 -3
- package/dist/routes/terminal/types.d.ts +2 -7
- package/dist/run/route-shell.d.ts +60 -0
- package/dist/run/route-shell.js +51 -0
- package/dist/run/run.d.ts +6 -1
- package/dist/run/run.js +11 -2
- package/dist/run/status.d.ts +2 -0
- package/dist/run/status.js +5 -0
- package/dist/study/composition-rules.js +1 -1
- package/dist/study/init-templates.d.ts +1 -1
- package/dist/study/init-templates.js +43 -34
- package/dist/study/init.js +1 -1
- package/dist/study/parse/subject.js +1 -1
- package/docs/architecture/actor-contract.md +1 -1
- package/docs/architecture/external-public-shared-world.md +1 -1
- package/docs/architecture/terminal-product-route.md +13 -13
- package/docs/contracts/study-analysis.md +5 -2
- package/docs/product/automatic-analysis.md +1 -1
- package/package.json +1 -1
|
@@ -21,39 +21,17 @@
|
|
|
21
21
|
// harness errors are redacted at this boundary; the bundle's `stream.actor` carries the
|
|
22
22
|
// conformant humanish.actor-trace.v1 projection, whose `redaction.screenshots` records the
|
|
23
23
|
// run's actual mode ("raw" | "blurred" | "n/a"), and every label downstream derives from it.
|
|
24
|
-
import { withTransientCommsSecrets } from "../../run/transient-comms-secrets.js";
|
|
25
24
|
import path from "node:path";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { resolveAutomaticAnalysis } from "../../analysis/automatic-config.js";
|
|
25
|
+
import {} from "../../run/run.js";
|
|
26
|
+
import { admitRoute, completeRefusalAnalysis } from "../../run/route-shell.js";
|
|
29
27
|
import { browserRouteScorer } from "../../study/adapter-scorer-loader.js";
|
|
30
28
|
import { withLateScorer } from "../../study/route-inputs.js";
|
|
31
|
-
import {
|
|
29
|
+
import {} from "./plan.js";
|
|
32
30
|
import { finishCuaRun } from "./result.js";
|
|
33
31
|
import { runStudyParticipants } from "./live-phase.js";
|
|
34
32
|
import { admitCuaRun, refuseCuaStudy, startCuaRun } from "./setup.js";
|
|
35
33
|
import {} from "./types.js";
|
|
36
34
|
import { studyResultIdentity } from "../../run/study-result.js";
|
|
37
|
-
/**
|
|
38
|
-
* Plans and runs a computer-use study in one call. It is not exported from src/index.ts; tests call
|
|
39
|
-
* it. It plans the config with planComputerUseStudy and runs
|
|
40
|
-
* the plan with runComputerUsePlan, whose run scope and withTransientCommsSecrets wrapper cover the
|
|
41
|
-
* run and its analysis.
|
|
42
|
-
*/
|
|
43
|
-
export async function runCuaActorStudy(options) {
|
|
44
|
-
const { config, dryRun, ...input } = options;
|
|
45
|
-
// planComputerUseStudy makes every configuration refusal, in the order this route always has.
|
|
46
|
-
const planned = planComputerUseStudy(config, {
|
|
47
|
-
dryRun,
|
|
48
|
-
hasRunSession: input.deps?.runSession !== undefined,
|
|
49
|
-
driving: callerDrivingOf(input),
|
|
50
|
-
...(input.countOverride === undefined ? {} : { countOverride: input.countOverride }),
|
|
51
|
-
...(input.rerun === undefined ? {} : { rerun: input.rerun }),
|
|
52
|
-
});
|
|
53
|
-
if (planned.ok)
|
|
54
|
-
return runComputerUsePlan(planned.plan, input, config);
|
|
55
|
-
return computerUseStudyRefusal(options, planned.refusal);
|
|
56
|
-
}
|
|
57
35
|
/**
|
|
58
36
|
* A refused computer-use study's result, at the refusal's stage: a before-scope refusal has its own
|
|
59
37
|
* envelope and no analysis record; the others come after the cwd checks, and the participant cap after
|
|
@@ -75,66 +53,27 @@ export async function computerUseStudyRefusal(options, refusal) {
|
|
|
75
53
|
error: { code: refusal.code, message: refusal.message },
|
|
76
54
|
};
|
|
77
55
|
// The other refusals come after the cwd checks, and the participant cap after the personas are read.
|
|
78
|
-
|
|
79
|
-
return completeAutomaticAnalysis(await refuseCuaStudy(options, refusal), undefined, analysis.ok ? analysis.config : undefined, options, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
|
|
56
|
+
return completeRefusalAnalysis(await refuseCuaStudy(options, refusal), config, options);
|
|
80
57
|
}
|
|
81
58
|
/**
|
|
82
59
|
* runStudyWith's step for a computer-use plan. It runs the plan's local checks (admitCuaRun: the
|
|
83
60
|
* participants, the preflight plan, the keys, the local agent, subject env and caps, and the
|
|
84
61
|
* local-tree archive) before any run scope opens, so the CLI can present their refusal before it
|
|
85
|
-
* loads a declared scorer, and returns the run that continues from them with that scorer.
|
|
86
|
-
|
|
87
|
-
export async function admitComputerUsePlan(plan, input, config) {
|
|
88
|
-
const admission = await admitCuaRun(plan, input, config);
|
|
89
|
-
if (!admission.ok)
|
|
90
|
-
return {
|
|
91
|
-
ok: false,
|
|
92
|
-
outcome: cuaOutcome(await completeCuaAnalysis(plan, input, admission.result, undefined)),
|
|
93
|
-
};
|
|
94
|
-
return {
|
|
95
|
-
ok: true,
|
|
96
|
-
run: async (scorer) => {
|
|
97
|
-
// The scorer joins the input only; the runSession, provider and desktop the checks admitted
|
|
98
|
-
// stay the ones the run uses.
|
|
99
|
-
const running = withLateScorer(input, scorer, browserRouteScorer);
|
|
100
|
-
return cuaOutcome(await runAdmittedCuaRun(plan, running, admission.admitted));
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function cuaOutcome(result) {
|
|
105
|
-
return { route: "computer-use", result };
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Run a computer-use plan: its local checks, then the run. The run scope in runAdmittedCuaRun
|
|
109
|
-
* finalizes any status record the run opened, on every exit, so a test or library caller does not
|
|
110
|
-
* leave the 5 s status cadence writing into a directory something else is deleting (an unrelated
|
|
111
|
-
* ENOTEMPTY). Participants, the brain, the subject, the caps and the residual config come from the
|
|
112
|
-
* plan. `config` is what the caller's createProvider and inProcess executor receive.
|
|
113
|
-
*/
|
|
114
|
-
export async function runComputerUsePlan(plan, input, config) {
|
|
115
|
-
const admission = await admitCuaRun(plan, input, config);
|
|
116
|
-
if (!admission.ok)
|
|
117
|
-
return completeCuaAnalysis(plan, input, admission.result, undefined);
|
|
118
|
-
return runAdmittedCuaRun(plan, input, admission.admitted);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Runs an admitted plan in its own run scope, then its automatic analysis. The
|
|
122
|
-
* withTransientCommsSecrets wrapper scopes any email secret the run registers to this run and its
|
|
123
|
-
* analysis.
|
|
62
|
+
* loads a declared scorer, and returns the run that continues from them with that scorer. The
|
|
63
|
+
* run and its analysis share one scope for the email secrets it registers.
|
|
124
64
|
*/
|
|
125
|
-
function
|
|
126
|
-
return withTransientCommsSecrets(async () => {
|
|
127
|
-
const { result, finished } = await runScope((scope) => runPlanInScope(plan, input, admitted, scope));
|
|
128
|
-
return completeCuaAnalysis(plan, input, result, finished);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
function completeCuaAnalysis(plan, input, result, finished) {
|
|
65
|
+
export function admitComputerUsePlan(plan, input, config) {
|
|
132
66
|
// A local VM study whose cleanup is unconfirmed records a skip instead of analyzing.
|
|
133
|
-
const
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
67
|
+
const analysisRefusal = input.localVm?.analysisRefusal;
|
|
68
|
+
return admitRoute({
|
|
69
|
+
route: "computer-use",
|
|
70
|
+
analysis: plan.analysis,
|
|
71
|
+
input,
|
|
72
|
+
admit: () => admitCuaRun(plan, input, config),
|
|
73
|
+
withScorer: (base, scorer) => withLateScorer(base, scorer, browserRouteScorer),
|
|
74
|
+
runInScope: (admitted, running, scope) => runPlanInScope(plan, running, admitted, scope),
|
|
75
|
+
...(analysisRefusal === undefined ? {} : { analysisRefusal }),
|
|
76
|
+
commsSecrets: true,
|
|
138
77
|
});
|
|
139
78
|
}
|
|
140
79
|
async function runPlanInScope(plan, input, admitted, scope) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type RunScope } from "../../run/run.js";
|
|
2
|
+
import type { RefusedStudy } from "../../run/route-shell.js";
|
|
2
3
|
import type { CuaActorDescriptor } from "../../actors/registry.js";
|
|
3
4
|
import type { StudyCommsEmail, StudyCommsExternal, StudyConfig } from "../../study/types.js";
|
|
4
5
|
import { type RunRerunLineage } from "../../run/bundle.js";
|
|
@@ -8,12 +9,12 @@ import type { ComputerUsePlan } from "../../study/plan-types.js";
|
|
|
8
9
|
import { trackRuntimeStreams, type LiveTraceFlush } from "./live-flush.js";
|
|
9
10
|
import { type CuaRunBundleBase } from "./bundle.js";
|
|
10
11
|
import { projectParticipantSubjects } from "./subject-projection.js";
|
|
11
|
-
import { type CuaActorStudyErrorCode, type CuaActorStudyResult, type CuaParticipantDeps, type CuaParticipantPlan, type DesktopParticipantRun, type CuaSubjectProjection, type CuaSubjectProvenanceArg, type ComputerUseRunInput
|
|
12
|
+
import { type CuaActorStudyErrorCode, type CuaActorStudyResult, type CuaParticipantDeps, type CuaParticipantPlan, type DesktopParticipantRun, type CuaSubjectProjection, type CuaSubjectProvenanceArg, type ComputerUseRunInput } from "./types.js";
|
|
12
13
|
/**
|
|
13
14
|
* The envelope of a refusal the plan left for after the cwd checks. The participant cap and
|
|
14
15
|
* in-process fan-out refusals come after the committed personas are read, so a persona-file error still wins.
|
|
15
16
|
*/
|
|
16
|
-
export declare function refuseCuaStudy(options:
|
|
17
|
+
export declare function refuseCuaStudy(options: ComputerUseRunInput & RefusedStudy, refusal: ComputerUseRefusal): Promise<CuaActorStudyResult>;
|
|
17
18
|
export type AdmittedCuaRun = Extract<Awaited<ReturnType<typeof admitCuaRun>>, {
|
|
18
19
|
ok: true;
|
|
19
20
|
}>["admitted"];
|
|
@@ -19,7 +19,7 @@ import { type E2BDesktopModule } from "../../substrates/e2b/sdk.js";
|
|
|
19
19
|
import { type DesktopResourceObservation } from "../../substrates/e2b/desktop-resources.js";
|
|
20
20
|
import { type DetachedTimers } from "../../substrates/detached.js";
|
|
21
21
|
import type { Brain, ComputerUsePlan, ComputerUseRunner, ResidualConfig } from "../../study/plan-types.js";
|
|
22
|
-
import { type StudyCommsEmail
|
|
22
|
+
import { type StudyCommsEmail } from "../../study/types.js";
|
|
23
23
|
import { type ObserverResult } from "../../observer/render.js";
|
|
24
24
|
import { type BundleRun, type RunBundle, type RunRerunLineage, type RunScorerProvenance, type RunSubjectProvenance, type RunSubjectStateStepRecord } from "../../run/bundle.js";
|
|
25
25
|
import { type RunDesktopGeometry } from "../../run/streams.js";
|
|
@@ -31,11 +31,6 @@ export declare const CUA_FANOUT_STRATEGY: "per-lane-worlds";
|
|
|
31
31
|
export declare const CUA_MAX_CONCURRENCY_ENV = "HUMANISH_CUA_MAX_CONCURRENCY";
|
|
32
32
|
export declare const DEFAULT_APP_URL_SESSION_TIMEOUT_MS: number;
|
|
33
33
|
export declare const MIN_DERIVED_SESSION_TIMEOUT_MS: number;
|
|
34
|
-
/**
|
|
35
|
-
* What a computer-use run takes besides its plan and config. The count override and rerun go to
|
|
36
|
-
* participant building with the config.
|
|
37
|
-
*/
|
|
38
|
-
export type ComputerUseRunInput = Omit<RunCuaActorStudyOptions, "config" | "dryRun">;
|
|
39
34
|
/**
|
|
40
35
|
* What runStudyWith's local VM study gives a computer-use run: the desktop each participant runs on, the
|
|
41
36
|
* reason automatic analysis must not run (the study's cleanup is unconfirmed), and the signal its
|
|
@@ -47,13 +42,14 @@ export interface LocalVmInput {
|
|
|
47
42
|
readonly analysisRefusal: () => AutomaticAnalysisRefusal | undefined;
|
|
48
43
|
readonly signal?: AbortSignal;
|
|
49
44
|
}
|
|
50
|
-
|
|
45
|
+
/**
|
|
46
|
+
* What a computer-use run takes besides its plan and config. The count override and rerun go to
|
|
47
|
+
* participant building with the config.
|
|
48
|
+
*/
|
|
49
|
+
export interface ComputerUseRunInput {
|
|
51
50
|
/** Cancels post-run analysis only. */
|
|
52
51
|
analysisSignal?: AbortSignal;
|
|
53
52
|
cwd: string;
|
|
54
|
-
config: StudyConfig;
|
|
55
|
-
/** Resolved upstream (scenario.mode + CLI override); defaults safe (dry-run). */
|
|
56
|
-
dryRun: boolean;
|
|
57
53
|
open?: boolean;
|
|
58
54
|
runId?: string;
|
|
59
55
|
/** CLI `--count` override for the homogeneous fan-out participant count (ignored when a `lanes`
|
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
import type { ScriptedPlan } from "../../study/plan-types.js";
|
|
2
2
|
import type { AdmittedPlan } from "../../run-study.js";
|
|
3
|
+
import { type RefusedStudy } from "../../run/route-shell.js";
|
|
3
4
|
import { type ScriptedRefusal } from "./plan.js";
|
|
4
|
-
import { type
|
|
5
|
-
/**
|
|
6
|
-
* The config-taking entry point. It plans, returns a refusal with the envelope the route has always
|
|
7
|
-
* returned at that refusal's stage, and otherwise runs the plan.
|
|
8
|
-
*/
|
|
9
|
-
export declare function runScriptedBrowserStudy(options: RunScriptedBrowserStudyOptions): Promise<ScriptedBrowserStudyResult>;
|
|
5
|
+
import { type ScriptedBrowserStudyResult, type ScriptedRunInput } from "./types.js";
|
|
10
6
|
/**
|
|
11
7
|
* A refused scripted study's result, at the refusal's stage: a before-scope refusal has its own field
|
|
12
8
|
* order and no analysis record; the others come after the output directory checks.
|
|
13
9
|
*/
|
|
14
|
-
export declare function scriptedStudyRefusal(options:
|
|
10
|
+
export declare function scriptedStudyRefusal(options: ScriptedRunInput & RefusedStudy, refusal: ScriptedRefusal): Promise<ScriptedBrowserStudyResult>;
|
|
15
11
|
/**
|
|
16
12
|
* runStudyWith's step for a scripted plan. It takes no scorer, and its local checks (keys, a browser)
|
|
17
13
|
* run inside the run, so it returns the run.
|
|
18
14
|
*/
|
|
19
|
-
export declare function admitScriptedPlan(plan: ScriptedPlan, input: ScriptedRunInput): AdmittedPlan<"scripted"
|
|
20
|
-
/**
|
|
21
|
-
* Run a scripted plan. The run scope gives a direct library caller the same status-record lifetime
|
|
22
|
-
* the CLI gets: returning from this function finalizes any record the run opened, whichever of its
|
|
23
|
-
* fail-closed exits it took. Each route opens its own scope; `runStudyWith` opens none. Without this a
|
|
24
|
-
* test or an adopter calling the route directly leaves
|
|
25
|
-
* the 5s cadence ticking into a directory something else is deleting, which surfaces as an
|
|
26
|
-
* unrelated ENOTEMPTY.
|
|
27
|
-
*/
|
|
28
|
-
export declare function runScriptedPlan(plan: ScriptedPlan, input: ScriptedRunInput): Promise<ScriptedBrowserStudyResult>;
|
|
15
|
+
export declare function admitScriptedPlan(plan: ScriptedPlan, input: ScriptedRunInput): Promise<AdmittedPlan<"scripted">>;
|
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
import { randomBytes } from "node:crypto";
|
|
18
18
|
import { realpath } from "node:fs/promises";
|
|
19
19
|
import path from "node:path";
|
|
20
|
-
import { completeAutomaticAnalysis } from "../../analysis/automatic-completion.js";
|
|
21
|
-
import { resolveAutomaticAnalysis } from "../../analysis/automatic-config.js";
|
|
22
20
|
import { redactText, toErrorMessage } from "../../evidence/redaction.js";
|
|
23
21
|
import { buildRunSource } from "../../run/bundle.js";
|
|
24
22
|
import { prepareSelectedOutputDirectory } from "../../run/contained-output.js";
|
|
25
|
-
import {
|
|
23
|
+
import {} from "../../run/run.js";
|
|
24
|
+
import { admitRoute, completeRefusalAnalysis } from "../../run/route-shell.js";
|
|
26
25
|
import { renderScriptedReviewMarkdown } from "./bundle.js";
|
|
27
|
-
import {
|
|
26
|
+
import {} from "./plan.js";
|
|
28
27
|
import { finishScriptedRun } from "./result.js";
|
|
29
28
|
import { UnsafeScriptedSessionResultError } from "./session-result.js";
|
|
30
29
|
import { prepareScriptedRun } from "./setup.js";
|
|
@@ -32,21 +31,6 @@ import { ScriptedSubject } from "./subject.js";
|
|
|
32
31
|
import { runScriptedSessions, writeSurfaceTraces } from "./surface-sessions.js";
|
|
33
32
|
import {} from "./types.js";
|
|
34
33
|
import { studyResultIdentity } from "../../run/study-result.js";
|
|
35
|
-
/**
|
|
36
|
-
* The config-taking entry point. It plans, returns a refusal with the envelope the route has always
|
|
37
|
-
* returned at that refusal's stage, and otherwise runs the plan.
|
|
38
|
-
*/
|
|
39
|
-
export async function runScriptedBrowserStudy(options) {
|
|
40
|
-
const { config, dryRun, ...input } = options;
|
|
41
|
-
// planScriptedStudy makes every configuration refusal, in the order this route always has.
|
|
42
|
-
const planned = planScriptedStudy(config, {
|
|
43
|
-
dryRun,
|
|
44
|
-
injectedBrowser: injectedBrowser(input.deps),
|
|
45
|
-
});
|
|
46
|
-
if (planned.ok)
|
|
47
|
-
return runScriptedPlan(planned.plan, input);
|
|
48
|
-
return scriptedStudyRefusal(options, planned.refusal);
|
|
49
|
-
}
|
|
50
34
|
/**
|
|
51
35
|
* A refused scripted study's result, at the refusal's stage: a before-scope refusal has its own field
|
|
52
36
|
* order and no analysis record; the others come after the output directory checks.
|
|
@@ -83,35 +67,19 @@ export async function scriptedStudyRefusal(options, refusal) {
|
|
|
83
67
|
warnings: [],
|
|
84
68
|
error: { code: refusal.code, message: refusal.message },
|
|
85
69
|
};
|
|
86
|
-
|
|
87
|
-
return completeAutomaticAnalysis(refused, undefined, analysis.ok ? analysis.config : undefined, options, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
|
|
70
|
+
return completeRefusalAnalysis(refused, config, options);
|
|
88
71
|
}
|
|
89
72
|
/**
|
|
90
73
|
* runStudyWith's step for a scripted plan. It takes no scorer, and its local checks (keys, a browser)
|
|
91
74
|
* run inside the run, so it returns the run.
|
|
92
75
|
*/
|
|
93
76
|
export function admitScriptedPlan(plan, input) {
|
|
94
|
-
return {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Run a scripted plan. The run scope gives a direct library caller the same status-record lifetime
|
|
104
|
-
* the CLI gets: returning from this function finalizes any record the run opened, whichever of its
|
|
105
|
-
* fail-closed exits it took. Each route opens its own scope; `runStudyWith` opens none. Without this a
|
|
106
|
-
* test or an adopter calling the route directly leaves
|
|
107
|
-
* the 5s cadence ticking into a directory something else is deleting, which surfaces as an
|
|
108
|
-
* unrelated ENOTEMPTY.
|
|
109
|
-
*/
|
|
110
|
-
export async function runScriptedPlan(plan, input) {
|
|
111
|
-
const { result, finished } = await runScope((scope) => runScriptedPlanInScope(plan, input, scope));
|
|
112
|
-
return completeAutomaticAnalysis(result, finished, plan.analysis?.config, input, {
|
|
113
|
-
...(plan.analysis === undefined ? {} : { trigger: plan.analysis.trigger }),
|
|
114
|
-
preferLargerOutput: plan.analysis?.preferLargerOutput === true,
|
|
77
|
+
return admitRoute({
|
|
78
|
+
route: "scripted",
|
|
79
|
+
analysis: plan.analysis,
|
|
80
|
+
input,
|
|
81
|
+
admit: () => ({ ok: true, admitted: plan }),
|
|
82
|
+
runInScope: runScriptedPlanInScope,
|
|
115
83
|
});
|
|
116
84
|
}
|
|
117
85
|
async function runScriptedPlanInScope(plan, input, scope) {
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import type { ActorCompletionReason, ActorStatus } from "../../actors/contract.js";
|
|
2
2
|
import type { StudyEvent } from "../../study/run-study-events.js";
|
|
3
3
|
import type { AutomaticAnalysisResult } from "../../analysis/automatic-completion.js";
|
|
4
|
-
import type { StudyConfig } from "../../study/types.js";
|
|
5
4
|
import type { ObserverResult } from "../../observer/render.js";
|
|
6
5
|
import type { RunSubjectProvenance } from "../../run/bundle.js";
|
|
7
6
|
import type { StudyDeps } from "../../study/study-deps.js";
|
|
8
7
|
import type { RunStudyHomes } from "../../study/run-study-homes.js";
|
|
9
8
|
import { type StudyResultIdentity } from "../../run/study-result.js";
|
|
10
9
|
/** What a scripted run takes besides its plan. The plan carries the config, dry run and study. */
|
|
11
|
-
export
|
|
12
|
-
export interface RunScriptedBrowserStudyOptions {
|
|
10
|
+
export interface ScriptedRunInput {
|
|
13
11
|
/** Cancels post-run analysis only. */
|
|
14
12
|
analysisSignal?: AbortSignal;
|
|
15
13
|
/** Reports the analysis window to onEvent; built by normalizeRunStudyOptions. */
|
|
16
14
|
emit?: (event: StudyEvent) => void;
|
|
17
15
|
cwd: string;
|
|
18
|
-
config: StudyConfig;
|
|
19
|
-
/** Resolved upstream (scenario.mode + CLI override); defaults safe (dry-run). */
|
|
20
|
-
dryRun: boolean;
|
|
21
16
|
open?: boolean;
|
|
22
17
|
runId?: string;
|
|
23
18
|
/** Keys and subject env for the run. Defaults to process.env. Values are scrubbed; names persist. */
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
+
import { type RefusedStudy } from "../../run/route-shell.js";
|
|
1
2
|
import { type SharedWorldRefusal } from "./plan.js";
|
|
2
3
|
import type { SharedWorldPlan } from "../../study/plan-types.js";
|
|
3
4
|
import type { AdmittedPlan } from "../../run-study.js";
|
|
4
5
|
import type { StudyConfig } from "../../study/types.js";
|
|
5
|
-
import { type ConcurrentSharedWorldStudyResult, type SharedWorldRunInput
|
|
6
|
-
/**
|
|
7
|
-
* The library entry for a shared-world study. It plans the config with planSharedWorldStudy and runs
|
|
8
|
-
* the plan with runSharedWorldPlan, whose run scope and withTransientCommsSecrets wrapper cover the
|
|
9
|
-
* run and its analysis.
|
|
10
|
-
*/
|
|
11
|
-
export declare function runConcurrentSharedWorld(options: RunConcurrentSharedWorldStudyOptions): Promise<ConcurrentSharedWorldStudyResult>;
|
|
6
|
+
import { type ConcurrentSharedWorldStudyResult, type SharedWorldRunInput } from "./types.js";
|
|
12
7
|
/** A refused shared-world study's result: the route's envelope, and a refusal's analysis record. */
|
|
13
|
-
export declare function sharedWorldStudyRefusal(options:
|
|
8
|
+
export declare function sharedWorldStudyRefusal(options: SharedWorldRunInput & RefusedStudy, refusal: SharedWorldRefusal): Promise<ConcurrentSharedWorldStudyResult>;
|
|
14
9
|
/**
|
|
15
10
|
* runStudyWith's step for a shared-world plan. It runs a live plan's local checks (the keys, a local
|
|
16
11
|
* agent's sign-in and the subject env) before any run scope opens, so the CLI can present their refusal before it loads a
|
|
17
|
-
* declared scorer, and returns the run that continues from them with that scorer.
|
|
12
|
+
* declared scorer, and returns the run that continues from them with that scorer. The run and its
|
|
13
|
+
* analysis share one scope for the email secrets it registers.
|
|
18
14
|
*/
|
|
19
15
|
export declare function admitSharedWorldPlan(plan: SharedWorldPlan, input: SharedWorldRunInput, config: StudyConfig): Promise<AdmittedPlan<"shared-world">>;
|
|
20
|
-
/** Run a shared-world plan: its local checks, then the run. */
|
|
21
|
-
export declare function runSharedWorldPlan(plan: SharedWorldPlan, input: SharedWorldRunInput, config: StudyConfig): Promise<ConcurrentSharedWorldStudyResult>;
|
|
@@ -34,15 +34,13 @@
|
|
|
34
34
|
// gate; humanish cannot tell synthetic from real data, so it makes no claim about real data.
|
|
35
35
|
import path from "node:path";
|
|
36
36
|
import { missingKeys, missingSubjectEnv } from "../../study/requirements.js";
|
|
37
|
-
import { completeAutomaticAnalysis } from "../../analysis/automatic-completion.js";
|
|
38
|
-
import { resolveAutomaticAnalysis } from "../../analysis/automatic-config.js";
|
|
39
37
|
import { scrubLiterals } from "../../evidence/redaction.js";
|
|
40
38
|
import { describeMissingKeys } from "../../keys/key-resolution.js";
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
39
|
+
import {} from "../../run/run.js";
|
|
40
|
+
import { admitRoute, completeRefusalAnalysis, } from "../../run/route-shell.js";
|
|
43
41
|
import { makeCuaRunBudget } from "../computer-use/participant-model.js";
|
|
44
42
|
import { runExternalPublicPlane } from "./external-public.js";
|
|
45
|
-
import {
|
|
43
|
+
import { sharedWorldDescriptorOf } from "./plan.js";
|
|
46
44
|
import { localAgentRefusal } from "../../actors/local-agent/readiness.js";
|
|
47
45
|
import { runProvisionedPlane } from "./provisioned.js";
|
|
48
46
|
import { concurrentStudyFailure, finishConcurrentRun } from "./result.js";
|
|
@@ -58,22 +56,6 @@ const LOCAL_AGENT_REFUSAL_CODES = {
|
|
|
58
56
|
unsupported: "HUMANISH_SHARED_WORLD_ACTOR_UNSUPPORTED",
|
|
59
57
|
"unpriced-cap": "HUMANISH_SHARED_WORLD_UNPRICED_CAP",
|
|
60
58
|
};
|
|
61
|
-
/**
|
|
62
|
-
* The library entry for a shared-world study. It plans the config with planSharedWorldStudy and runs
|
|
63
|
-
* the plan with runSharedWorldPlan, whose run scope and withTransientCommsSecrets wrapper cover the
|
|
64
|
-
* run and its analysis.
|
|
65
|
-
*/
|
|
66
|
-
export async function runConcurrentSharedWorld(options) {
|
|
67
|
-
const { config, dryRun, ...input } = options;
|
|
68
|
-
// planSharedWorldStudy makes every configuration refusal, in the order this route always has.
|
|
69
|
-
const planned = planSharedWorldStudy(config, {
|
|
70
|
-
dryRun,
|
|
71
|
-
hasRunSession: input.deps?.runSession !== undefined,
|
|
72
|
-
});
|
|
73
|
-
if (planned.ok)
|
|
74
|
-
return runSharedWorldPlan(planned.plan, input, config);
|
|
75
|
-
return sharedWorldStudyRefusal(options, planned.refusal);
|
|
76
|
-
}
|
|
77
59
|
/** A refused shared-world study's result: the route's envelope, and a refusal's analysis record. */
|
|
78
60
|
export function sharedWorldStudyRefusal(options, refusal) {
|
|
79
61
|
const { config, dryRun } = options;
|
|
@@ -89,42 +71,38 @@ export function sharedWorldStudyRefusal(options, refusal) {
|
|
|
89
71
|
dryRun,
|
|
90
72
|
runId: options.runId,
|
|
91
73
|
});
|
|
92
|
-
|
|
93
|
-
const analysis = resolveAutomaticAnalysis(config.review?.analysis);
|
|
94
|
-
return completeAutomaticAnalysis(fail(refusal.code, refusal.message, refusal.actor), undefined, analysis.ok ? analysis.config : undefined, options, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
|
|
74
|
+
return completeRefusalAnalysis(fail(refusal.code, refusal.message, refusal.actor), config, options);
|
|
95
75
|
}
|
|
96
76
|
/**
|
|
97
77
|
* runStudyWith's step for a shared-world plan. It runs a live plan's local checks (the keys, a local
|
|
98
78
|
* agent's sign-in and the subject env) before any run scope opens, so the CLI can present their refusal before it loads a
|
|
99
|
-
* declared scorer, and returns the run that continues from them with that scorer.
|
|
79
|
+
* declared scorer, and returns the run that continues from them with that scorer. The run and its
|
|
80
|
+
* analysis share one scope for the email secrets it registers.
|
|
100
81
|
*/
|
|
101
|
-
export
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return { route: "shared-world", result };
|
|
112
|
-
}
|
|
113
|
-
/** Run a shared-world plan: its local checks, then the run. */
|
|
114
|
-
export async function runSharedWorldPlan(plan, input, config) {
|
|
115
|
-
const refused = await admitSharedWorldRun(plan, input);
|
|
116
|
-
return refused ?? runAdmittedSharedWorldRun(plan, input, config);
|
|
82
|
+
export function admitSharedWorldPlan(plan, input, config) {
|
|
83
|
+
return admitRoute({
|
|
84
|
+
route: "shared-world",
|
|
85
|
+
analysis: plan.analysis,
|
|
86
|
+
input,
|
|
87
|
+
admit: () => admitSharedWorldRun(plan, input),
|
|
88
|
+
withScorer: (base, scorer) => withLateScorer(base, scorer, browserRouteScorer),
|
|
89
|
+
runInScope: (_admitted, running, scope) => runPlanInScope(plan, running, config, scope),
|
|
90
|
+
commsSecrets: true,
|
|
91
|
+
});
|
|
117
92
|
}
|
|
118
93
|
/**
|
|
119
94
|
* A live plan's local checks, made outside any run scope: the keys, a local agent's sign-in, then
|
|
120
|
-
* the subject env.
|
|
121
|
-
* record of a run that never started.
|
|
95
|
+
* the subject env.
|
|
122
96
|
*/
|
|
123
97
|
async function admitSharedWorldRun(plan, input) {
|
|
98
|
+
const admitted = { ok: true, admitted: undefined };
|
|
124
99
|
if (plan.dryRun)
|
|
125
|
-
return
|
|
100
|
+
return admitted;
|
|
126
101
|
const env = input.env ?? process.env;
|
|
127
|
-
const fail = (code, message) =>
|
|
102
|
+
const fail = (code, message) => ({
|
|
103
|
+
ok: false,
|
|
104
|
+
result: sharedWorldFailure(plan, input)(code, message, sharedWorldDescriptorOf(plan.actor).id),
|
|
105
|
+
});
|
|
128
106
|
// The plan lists OPENAI_API_KEY for an openai brain's participants and the external-public
|
|
129
107
|
// plane's lobby-code reader; a local-agent brain's participants run on the operator's signed-in
|
|
130
108
|
// agent instead.
|
|
@@ -143,24 +121,7 @@ async function admitSharedWorldRun(plan, input) {
|
|
|
143
121
|
if (unsetSubjectEnv.length > 0) {
|
|
144
122
|
return fail("HUMANISH_SHARED_WORLD_SUBJECT_ENV_MISSING", `subject.env declares ${unsetSubjectEnv.join(", ")} but the environment does not provide ${unsetSubjectEnv.length === 1 ? "it" : "them"} (pass via --dotenv; values are never persisted).`);
|
|
145
123
|
}
|
|
146
|
-
return
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Runs an admitted plan in its own run scope, then its automatic analysis. The
|
|
150
|
-
* withTransientCommsSecrets wrapper scopes any email secret the run registers to this run and its
|
|
151
|
-
* analysis.
|
|
152
|
-
*/
|
|
153
|
-
function runAdmittedSharedWorldRun(plan, input, config) {
|
|
154
|
-
return withTransientCommsSecrets(async () => {
|
|
155
|
-
const { result, finished } = await runScope((scope) => runPlanInScope(plan, input, config, scope));
|
|
156
|
-
return completeSharedWorldAnalysis(plan, input, result, finished);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
function completeSharedWorldAnalysis(plan, input, result, finished) {
|
|
160
|
-
return completeAutomaticAnalysis(result, finished, plan.analysis?.config, input, {
|
|
161
|
-
...(plan.analysis === undefined ? {} : { trigger: plan.analysis.trigger }),
|
|
162
|
-
preferLargerOutput: plan.analysis?.preferLargerOutput === true,
|
|
163
|
-
});
|
|
124
|
+
return admitted;
|
|
164
125
|
}
|
|
165
126
|
/** The route's envelope for a run that stops before its bundle. */
|
|
166
127
|
function sharedWorldFailure(plan, input) {
|
|
@@ -24,13 +24,11 @@ export declare const CONCURRENT_SHARED_WORLD_PROVIDER_METADATA: {
|
|
|
24
24
|
readonly tool: "humanish";
|
|
25
25
|
};
|
|
26
26
|
export declare const CONCURRENT_ATTRIBUTION_LIMITS: readonly ["concurrent", "best-effort-causal-attribution", "non-deterministic-shared-state", "window-and-snapshot-granularity", "contention-observed-not-proven-safe", "state-change-not-isolated-to-actors"];
|
|
27
|
-
|
|
27
|
+
/** What a shared-world run takes besides its plan. The plan carries the config, dry run and study. */
|
|
28
|
+
export interface SharedWorldRunInput {
|
|
28
29
|
/** Cancels post-run analysis only. */
|
|
29
30
|
analysisSignal?: AbortSignal;
|
|
30
31
|
cwd: string;
|
|
31
|
-
config: StudyConfig;
|
|
32
|
-
/** Resolved upstream (scenario.mode + CLI override); defaults safe (dry-run). */
|
|
33
|
-
dryRun: boolean;
|
|
34
32
|
open?: boolean;
|
|
35
33
|
runId?: string;
|
|
36
34
|
onObserverReady?: (observer: ObserverResult & {
|
|
@@ -56,8 +54,6 @@ export interface RunConcurrentSharedWorldStudyOptions {
|
|
|
56
54
|
* core-stamped onto the bundle as evidence. Absent for library callers. */
|
|
57
55
|
scorerProvenance?: RunScorerProvenance;
|
|
58
56
|
}
|
|
59
|
-
/** What a shared-world run takes besides its plan. The plan carries the config, dry run and study. */
|
|
60
|
-
export type SharedWorldRunInput = Omit<RunConcurrentSharedWorldStudyOptions, "config" | "dryRun">;
|
|
61
57
|
export type ConcurrentSharedWorldStudyErrorCode = "HUMANISH_STUDY_ANALYSIS_INVALID" | "HUMANISH_STUDY_TASKS_UNSUPPORTED" | "HUMANISH_STUDY_OPTION_UNSUPPORTED" | "HUMANISH_STUDY_V2_UNSUPPORTED" | "HUMANISH_SHARED_WORLD_FAILED" | "HUMANISH_SHARED_WORLD_ACTOR_UNSUPPORTED" | "HUMANISH_SHARED_WORLD_INVALID" | "HUMANISH_SHARED_WORLD_KEYS_MISSING"
|
|
62
58
|
/** A local-agent brain's CLI is not on `PATH`. */
|
|
63
59
|
| "HUMANISH_SHARED_WORLD_AGENT_MISSING"
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
+
import { type RefusedStudy } from "../../run/route-shell.js";
|
|
1
2
|
import { type TerminalRefusal } from "./plan.js";
|
|
2
3
|
import type { TerminalPlan } from "../../study/plan-types.js";
|
|
3
4
|
import type { AdmittedPlan } from "../../run-study.js";
|
|
4
|
-
import { type
|
|
5
|
-
/**
|
|
6
|
-
* The config-taking entry point. It plans, returns a refusal with the same envelope and analysis
|
|
7
|
-
* record the route has always returned, and otherwise runs the plan.
|
|
8
|
-
*/
|
|
9
|
-
export declare function runTerminalProductStudy(options: RunTerminalProductStudyOptions): Promise<TerminalProductStudyResult>;
|
|
5
|
+
import { type TerminalProductStudyResult, type TerminalRunInput } from "./types.js";
|
|
10
6
|
/** A refused terminal study's result: the route's envelope, and the analysis record a refusal gets. */
|
|
11
|
-
export declare function terminalStudyRefusal(options:
|
|
12
|
-
/**
|
|
13
|
-
* Run a terminal plan. The run scope gives a direct library caller the same run lifetime the CLI
|
|
14
|
-
* gets: whichever of its fail-closed exits the run takes, the run it started is closed, and only a
|
|
15
|
-
* run that published its final bundle reaches automatic analysis.
|
|
16
|
-
*/
|
|
17
|
-
export declare function runTerminalPlan(plan: TerminalPlan, input: TerminalRunInput): Promise<TerminalProductStudyResult>;
|
|
7
|
+
export declare function terminalStudyRefusal(options: TerminalRunInput & RefusedStudy, refusal: TerminalRefusal): Promise<TerminalProductStudyResult>;
|
|
18
8
|
/**
|
|
19
9
|
* runStudyWith's step for a terminal plan. It runs a live plan's local checks (checkLiveTerminalMachine)
|
|
20
10
|
* before any run scope opens, so the CLI can present their refusal before it loads a declared
|