humanish 0.80.0 → 0.82.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.
- package/README.md +121 -615
- package/dist/actor-contract.d.ts +30 -0
- package/dist/actor-contract.js.map +1 -1
- package/dist/chrome-cdp-probe.js +13 -0
- package/dist/chrome-cdp-probe.js.map +1 -1
- package/dist/computer-use.d.ts +13 -3
- package/dist/computer-use.js +179 -15
- package/dist/computer-use.js.map +1 -1
- package/dist/cua-actor-lab.d.ts +20 -8
- package/dist/cua-actor-lab.js +154 -49
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/e2b-desktop-executor.d.ts +9 -1
- package/dist/e2b-desktop-executor.js +67 -4
- package/dist/e2b-desktop-executor.js.map +1 -1
- package/dist/e2b-desktop-launch.d.ts +36 -1
- package/dist/e2b-desktop-launch.js +88 -1
- package/dist/e2b-desktop-launch.js.map +1 -1
- package/dist/e2b-desktop-resources.d.ts +11 -0
- package/dist/e2b-desktop-resources.js +33 -0
- package/dist/e2b-desktop-resources.js.map +1 -0
- package/dist/e2b-desktop-screenshot-cleanup.d.ts +15 -0
- package/dist/e2b-desktop-screenshot-cleanup.js +67 -0
- package/dist/e2b-desktop-screenshot-cleanup.js.map +1 -0
- package/dist/e2b-terminal-lab.d.ts +5 -2
- package/dist/e2b-terminal-lab.js +238 -86
- package/dist/e2b-terminal-lab.js.map +1 -1
- package/dist/first-run-path.js +2 -2
- package/dist/first-run-path.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lab-config.d.ts +15 -14
- package/dist/lab-config.js +11 -2
- package/dist/lab-config.js.map +1 -1
- package/dist/observer-data.d.ts +2 -0
- package/dist/observer-data.js +10 -1
- package/dist/observer-data.js.map +1 -1
- package/dist/openai-responses-cu.js +76 -49
- package/dist/openai-responses-cu.js.map +1 -1
- package/dist/pricing.d.ts +19 -1
- package/dist/pricing.js +43 -10
- package/dist/pricing.js.map +1 -1
- package/dist/program.js +17 -8
- package/dist/program.js.map +1 -1
- package/dist/redaction.js +9 -2
- package/dist/redaction.js.map +1 -1
- package/dist/run.d.ts +14 -2
- package/dist/run.js.map +1 -1
- package/dist/terminal-node-bootstrap.d.ts +4 -0
- package/dist/terminal-node-bootstrap.js +58 -0
- package/dist/terminal-node-bootstrap.js.map +1 -0
- package/dist/terminal-runtime-auth.d.ts +13 -0
- package/dist/terminal-runtime-auth.js +24 -0
- package/dist/terminal-runtime-auth.js.map +1 -0
- package/dist/terminal-runtime.d.ts +16 -0
- package/dist/terminal-runtime.js +42 -0
- package/dist/terminal-runtime.js.map +1 -0
- package/dist/terminal-token-usage.d.ts +2 -1
- package/dist/terminal-token-usage.js +3 -2
- package/dist/terminal-token-usage.js.map +1 -1
- package/docs/architecture/actor-contract.md +22 -0
- package/docs/architecture/state-driven-executor.md +10 -1
- package/docs/architecture/terminal-product-lane.md +142 -6
- package/docs/contracts/feedback.md +14 -0
- package/docs/contracts/run-bundle.md +5 -1
- package/docs/contracts/schemas.md +17 -8
- package/docs/goals/current.md +61 -13
- package/docs/ramp/README.md +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const TERMINAL_NODE_VERSION = "22.23.2";
|
|
2
|
+
export declare const TERMINAL_NODE_NPM_PREFIX_SCRIPT: string;
|
|
3
|
+
/** Unkeyed runtime prerequisite for stock Linux desktops. No apt repository refresh (#674). */
|
|
4
|
+
export declare const TERMINAL_NODE_BOOTSTRAP_COMMAND: string;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Node 22 remains a supported LTS line. Pin the official release and trusted archive hashes:
|
|
2
|
+
// https://nodejs.org/en/about/previous-releases
|
|
3
|
+
// https://nodejs.org/dist/v22.23.2/SHASUMS256.txt (checked 2026-09-05)
|
|
4
|
+
// A checksum fetched alongside the archive at runtime would not pin what we trust.
|
|
5
|
+
export const TERMINAL_NODE_VERSION = "22.23.2";
|
|
6
|
+
// npm normally derives its global prefix from the real Node executable. This distribution
|
|
7
|
+
// lives under /opt, while its public executables use /usr/local/bin. Set only a missing
|
|
8
|
+
// built-in default; npm's environment, CLI, user and global config still take precedence.
|
|
9
|
+
export const TERMINAL_NODE_NPM_PREFIX_SCRIPT = [
|
|
10
|
+
'const fs = require("node:fs");',
|
|
11
|
+
'const file = process.argv[1];',
|
|
12
|
+
'let existing = "";',
|
|
13
|
+
'try { existing = fs.readFileSync(file, "utf8"); } catch (error) { if (error.code !== "ENOENT") throw error; }',
|
|
14
|
+
'if (!/^[\\t ]*prefix[\\t ]*=/m.test(existing)) fs.appendFileSync(file, "\\nprefix=/usr/local\\n");'
|
|
15
|
+
].join(" ");
|
|
16
|
+
/** Unkeyed runtime prerequisite for stock Linux desktops. No apt repository refresh (#674). */
|
|
17
|
+
export const TERMINAL_NODE_BOOTSTRAP_COMMAND = [
|
|
18
|
+
"set -eu",
|
|
19
|
+
"# humanish terminal-node-bootstrap",
|
|
20
|
+
"node_major=0",
|
|
21
|
+
`if command -v node >/dev/null 2>&1; then node_major=$(node -e 'console.log(Number(process.versions.node.split(".")[0]))' 2>/dev/null || echo 0); fi`,
|
|
22
|
+
`if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1 && [ "$node_major" -ge 20 ] && npm --version >/dev/null 2>&1; then`,
|
|
23
|
+
// An explicit exit under set -e runs the stock login shell's failing clear_console logout hook
|
|
24
|
+
// and turns this successful fast path into exit 1. Finish the compound command naturally.
|
|
25
|
+
" :",
|
|
26
|
+
"else",
|
|
27
|
+
`case "$(uname -s):$(uname -m)" in`,
|
|
28
|
+
` Linux:x86_64) node_arch=x64; node_sha=b294a556e639d64338823920e5866c21c02741742d2e1529ee1a225c1ec9252a ;;`,
|
|
29
|
+
` Linux:aarch64|Linux:arm64) node_arch=arm64; node_sha=013b59cfd2819703a6f4a14ab891fc46fc2a4e3f5bcd92de3fb4929b43e35b30 ;;`,
|
|
30
|
+
` *) echo 'humanish: terminal runtime requires a supported Linux x64/arm64 desktop or working Node >=20 and npm' >&2; exit 1 ;;`,
|
|
31
|
+
"esac",
|
|
32
|
+
"for prerequisite in curl sha256sum tar gzip mktemp sudo; do",
|
|
33
|
+
` command -v "$prerequisite" >/dev/null 2>&1 || { echo "humanish: terminal runtime bootstrap requires $prerequisite" >&2; exit 1; }`,
|
|
34
|
+
"done",
|
|
35
|
+
`node_archive="node-v${TERMINAL_NODE_VERSION}-linux-$node_arch.tar.gz"`,
|
|
36
|
+
`node_target="/opt/humanish/node-v${TERMINAL_NODE_VERSION}-linux-$node_arch"`,
|
|
37
|
+
`node_temp=$(mktemp -d /tmp/humanish-node.XXXXXX)`,
|
|
38
|
+
`trap 'rm -rf "$node_temp"' EXIT`,
|
|
39
|
+
`curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' --connect-timeout 10 --max-time 90 --retry 1 --retry-max-time 120 --output "$node_temp/$node_archive" "https://nodejs.org/dist/v${TERMINAL_NODE_VERSION}/$node_archive"`,
|
|
40
|
+
`(cd "$node_temp" && printf '%s %s\\n' "$node_sha" "$node_archive" | sha256sum --check --status) || { echo 'humanish: terminal Node archive checksum did not match the trusted release' >&2; exit 1; }`,
|
|
41
|
+
// Only a verified official archive reaches privileged extraction. The versioned install is
|
|
42
|
+
// root-owned; subsequent ordinary and sudo shells find it through standard /usr/local/bin.
|
|
43
|
+
"sudo -n mkdir -p /opt/humanish /usr/local/bin",
|
|
44
|
+
`sudo -n tar --extract --gzip --file "$node_temp/$node_archive" --directory /opt/humanish --no-same-owner`,
|
|
45
|
+
"for executable in node npm npx; do",
|
|
46
|
+
` sudo -n ln -sfn "$node_target/bin/$executable" "/usr/local/bin/$executable"`,
|
|
47
|
+
"done",
|
|
48
|
+
// Keep global product executables on the existing ordinary/sudo PATH (#679). The new
|
|
49
|
+
// versioned distribution is the only config we modify; no user/global npmrc or profile.
|
|
50
|
+
`sudo -n "$node_target/bin/node" -e '${TERMINAL_NODE_NPM_PREFIX_SCRIPT}' "$node_target/lib/node_modules/npm/npmrc"`,
|
|
51
|
+
"hash -r",
|
|
52
|
+
`node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' && npm --version >/dev/null`,
|
|
53
|
+
// Product installation already uses sudo; detect a template whose sudo PATH cannot see Node
|
|
54
|
+
// rather than changing global PATH or permissions to make it look supported.
|
|
55
|
+
`sudo -n node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' && sudo -n npm --version >/dev/null`,
|
|
56
|
+
"fi"
|
|
57
|
+
].join("\n");
|
|
58
|
+
//# sourceMappingURL=terminal-node-bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-node-bootstrap.js","sourceRoot":"","sources":["../src/terminal-node-bootstrap.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,gDAAgD;AAChD,uEAAuE;AACvE,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAE/C,0FAA0F;AAC1F,wFAAwF;AACxF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,gCAAgC;IAChC,+BAA+B;IAC/B,oBAAoB;IACpB,+GAA+G;IAC/G,oGAAoG;CACrG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,+FAA+F;AAC/F,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,SAAS;IACT,oCAAoC;IACpC,cAAc;IACd,qJAAqJ;IACrJ,yIAAyI;IACzI,+FAA+F;IAC/F,0FAA0F;IAC1F,KAAK;IACL,MAAM;IACN,mCAAmC;IACnC,6GAA6G;IAC7G,4HAA4H;IAC5H,iIAAiI;IACjI,MAAM;IACN,6DAA6D;IAC7D,qIAAqI;IACrI,MAAM;IACN,uBAAuB,qBAAqB,2BAA2B;IACvE,oCAAoC,qBAAqB,oBAAoB;IAC7E,kDAAkD;IAClD,iCAAiC;IACjC,wNAAwN,qBAAqB,iBAAiB;IAC9P,wMAAwM;IACxM,2FAA2F;IAC3F,2FAA2F;IAC3F,+CAA+C;IAC/C,0GAA0G;IAC1G,oCAAoC;IACpC,+EAA+E;IAC/E,MAAM;IACN,qFAAqF;IACrF,wFAAwF;IACxF,uCAAuC,+BAA+B,6CAA6C;IACnH,SAAS;IACT,+GAA+G;IAC/G,4FAA4F;IAC5F,6EAA6E;IAC7E,+HAA+H;IAC/H,IAAI;CACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { E2BNetworkOptions } from "./e2b-desktop-launch.js";
|
|
2
|
+
export declare const OPENAI_EGRESS_HOST = "api.openai.com";
|
|
3
|
+
/** E2B envd installs the sandbox-specific proxy CA into this system bundle before routing. */
|
|
4
|
+
export declare const E2B_SYSTEM_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
|
|
5
|
+
/** An inert nonsecret value satisfies Codex exec's auth prerequisite. E2B replaces the header. */
|
|
6
|
+
export declare const OPENAI_EGRESS_PLACEHOLDER = "humanish-egress-auth-placeholder";
|
|
7
|
+
/**
|
|
8
|
+
* Keep the runtime key in the host-side E2B request, outside sandbox env/files. The installed
|
|
9
|
+
* E2B SDK declares that transform headers override existing request headers. This adds no routing
|
|
10
|
+
* restrictions: every sandbox process can still spend via the provider proxy. Never log the
|
|
11
|
+
* returned options. An adopter's existing exact-host rule must not be silently overwritten.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildOpenAiEgressNetwork(keyValue: string, existing?: E2BNetworkOptions): E2BNetworkOptions;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const OPENAI_EGRESS_HOST = "api.openai.com";
|
|
2
|
+
/** E2B envd installs the sandbox-specific proxy CA into this system bundle before routing. */
|
|
3
|
+
export const E2B_SYSTEM_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
|
|
4
|
+
/** An inert nonsecret value satisfies Codex exec's auth prerequisite. E2B replaces the header. */
|
|
5
|
+
export const OPENAI_EGRESS_PLACEHOLDER = "humanish-egress-auth-placeholder";
|
|
6
|
+
/**
|
|
7
|
+
* Keep the runtime key in the host-side E2B request, outside sandbox env/files. The installed
|
|
8
|
+
* E2B SDK declares that transform headers override existing request headers. This adds no routing
|
|
9
|
+
* restrictions: every sandbox process can still spend via the provider proxy. Never log the
|
|
10
|
+
* returned options. An adopter's existing exact-host rule must not be silently overwritten.
|
|
11
|
+
*/
|
|
12
|
+
export function buildOpenAiEgressNetwork(keyValue, existing) {
|
|
13
|
+
if (Object.keys(existing?.rules ?? {}).some((host) => host.toLowerCase().replace(/\.$/, "") === OPENAI_EGRESS_HOST)) {
|
|
14
|
+
throw new Error("openai-egress conflicts with an existing api.openai.com network rule; refusing to overwrite it.");
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
...existing,
|
|
18
|
+
rules: {
|
|
19
|
+
...existing?.rules,
|
|
20
|
+
[OPENAI_EGRESS_HOST]: [{ transform: { headers: { Authorization: `Bearer ${keyValue}` } } }]
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=terminal-runtime-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-runtime-auth.js","sourceRoot":"","sources":["../src/terminal-runtime-auth.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AACnD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,oCAAoC,CAAC;AACzE,kGAAkG;AAClG,MAAM,CAAC,MAAM,yBAAyB,GAAG,kCAAkC,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAgB,EAChB,QAA4B;IAE5B,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,kBAAkB,CAAC,EAAE,CAAC;QACpH,MAAM,IAAI,KAAK,CAAC,iGAAiG,CAAC,CAAC;IACrH,CAAC;IACD,OAAO;QACL,GAAG,QAAQ;QACX,KAAK,EAAE;YACL,GAAG,QAAQ,EAAE,KAAK;YAClB,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC;SAC5F;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ActorRuntimeProvenance } from "./actor-contract.js";
|
|
2
|
+
import type { ReasoningEffort } from "./reasoning-effort.js";
|
|
3
|
+
export declare const TERMINAL_RUNTIME_PACKAGE = "@openai/codex";
|
|
4
|
+
export declare const TERMINAL_RUNTIME_VERSION_TIMEOUT_MS = 60000;
|
|
5
|
+
/** Exact semver only: no registry tags, ranges, URLs, or shell syntax. */
|
|
6
|
+
export declare function isExactRuntimeVersion(value: unknown): value is string;
|
|
7
|
+
/** Captured Codex CLI output: `codex-cli 0.153.3\n`. Other shapes fail closed. */
|
|
8
|
+
export declare function parseTerminalRuntimeVersion(stdout: string): string | undefined;
|
|
9
|
+
export declare function shellQuote(value: string): string;
|
|
10
|
+
export declare function buildRuntimeVersionCommand(requestedVersion?: string): string;
|
|
11
|
+
export declare function buildRuntimeExecPrefix(version: string, model?: string, reasoningEffort?: ReasoningEffort): string;
|
|
12
|
+
export declare function declaredRuntimeProvenance(args: {
|
|
13
|
+
version?: string;
|
|
14
|
+
model?: string;
|
|
15
|
+
reasoningEffort?: ReasoningEffort;
|
|
16
|
+
}): ActorRuntimeProvenance;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const TERMINAL_RUNTIME_PACKAGE = "@openai/codex";
|
|
2
|
+
export const TERMINAL_RUNTIME_VERSION_TIMEOUT_MS = 60_000;
|
|
3
|
+
/** Exact semver only: no registry tags, ranges, URLs, or shell syntax. */
|
|
4
|
+
export function isExactRuntimeVersion(value) {
|
|
5
|
+
if (typeof value !== "string" || value.length > 120)
|
|
6
|
+
return false;
|
|
7
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/.exec(value);
|
|
8
|
+
return match !== null && (match[4]?.split(".").every((part) => !/^\d+$/.test(part) || part === "0" || !part.startsWith("0")) ?? true);
|
|
9
|
+
}
|
|
10
|
+
/** Captured Codex CLI output: `codex-cli 0.153.3\n`. Other shapes fail closed. */
|
|
11
|
+
export function parseTerminalRuntimeVersion(stdout) {
|
|
12
|
+
const match = /^codex-cli ([^\s]+)$/.exec(stdout.trim());
|
|
13
|
+
return match && isExactRuntimeVersion(match[1]) ? match[1] : undefined;
|
|
14
|
+
}
|
|
15
|
+
export function shellQuote(value) {
|
|
16
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
17
|
+
}
|
|
18
|
+
export function buildRuntimeVersionCommand(requestedVersion) {
|
|
19
|
+
if (requestedVersion !== undefined && !isExactRuntimeVersion(requestedVersion))
|
|
20
|
+
throw new Error("Invalid exact Codex runtime version.");
|
|
21
|
+
return `npm_config_update_notifier=false npx -y ${TERMINAL_RUNTIME_PACKAGE}@${requestedVersion ?? "latest"} --version`;
|
|
22
|
+
}
|
|
23
|
+
export function buildRuntimeExecPrefix(version, model, reasoningEffort) {
|
|
24
|
+
if (!isExactRuntimeVersion(version))
|
|
25
|
+
throw new Error("Codex execution requires a verified exact runtime version.");
|
|
26
|
+
return `npm_config_update_notifier=false npx -y ${TERMINAL_RUNTIME_PACKAGE}@${version} exec`
|
|
27
|
+
+ (model === undefined ? "" : ` --model ${shellQuote(model)}`)
|
|
28
|
+
+ (reasoningEffort === undefined ? "" : ` -c ${shellQuote(`model_reasoning_effort=${JSON.stringify(reasoningEffort)}`)}`);
|
|
29
|
+
}
|
|
30
|
+
export function declaredRuntimeProvenance(args) {
|
|
31
|
+
return {
|
|
32
|
+
schema: "humanish.actor-runtime.v1",
|
|
33
|
+
package: TERMINAL_RUNTIME_PACKAGE,
|
|
34
|
+
requestedVersion: args.version ?? "latest",
|
|
35
|
+
versionStatus: "unobserved",
|
|
36
|
+
...(args.model === undefined ? {} : { requestedModel: args.model }),
|
|
37
|
+
modelStatus: args.model === undefined ? "runtime_default_unobserved" : "declared",
|
|
38
|
+
...(args.reasoningEffort === undefined ? {} : { requestedReasoningEffort: args.reasoningEffort }),
|
|
39
|
+
usageGranularity: "runtime_turn"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=terminal-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-runtime.js","sourceRoot":"","sources":["../src/terminal-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ActorTokenUsage } from "./actor-contract.js";
|
|
2
2
|
/**
|
|
3
|
-
* Accumulate
|
|
3
|
+
* Accumulate runtime-turn usage from a captured `codex exec --json` stream. A Codex turn may
|
|
4
|
+
* include multiple provider requests; these records cannot establish per-request pricing tiers.
|
|
4
5
|
*
|
|
5
6
|
* Returns undefined when the stream carried no usage record at all, which is the honest "no
|
|
6
7
|
* signal" case and must stay distinguishable from a measured zero. Per-turn records are preserved
|
|
@@ -21,7 +21,8 @@ function num(value) {
|
|
|
21
21
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Accumulate
|
|
24
|
+
* Accumulate runtime-turn usage from a captured `codex exec --json` stream. A Codex turn may
|
|
25
|
+
* include multiple provider requests; these records cannot establish per-request pricing tiers.
|
|
25
26
|
*
|
|
26
27
|
* Returns undefined when the stream carried no usage record at all, which is the honest "no
|
|
27
28
|
* signal" case and must stay distinguishable from a measured zero. Per-turn records are preserved
|
|
@@ -88,6 +89,6 @@ export function describeTokenUsage(usage) {
|
|
|
88
89
|
if (usage.output !== undefined)
|
|
89
90
|
parts.push(`${usage.output.toLocaleString("en-US")} output`);
|
|
90
91
|
const turns = usage.turns?.length ?? 0;
|
|
91
|
-
return `${parts.join(", ")} tokens over ${turns}
|
|
92
|
+
return `${parts.join(", ")} tokens over ${turns} Codex turn${turns === 1 ? "" : "s"}`;
|
|
92
93
|
}
|
|
93
94
|
//# sourceMappingURL=terminal-token-usage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-token-usage.js","sourceRoot":"","sources":["../src/terminal-token-usage.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,6FAA6F;AAC7F,iGAAiG;AACjG,+FAA+F;AAC/F,kGAAkG;AAClG,6FAA6F;AAC7F,EAAE;AACF,8FAA8F;AAC9F,0FAA0F;AAC1F,2FAA2F;AAC3F,EAAE;AACF,mGAAmG;AACnG,iGAAiG;AACjG,wFAAwF;AACxF,iEAAiE;AAcjE,iGAAiG;AACjG,2FAA2F;AAC3F,MAAM,QAAQ,GAAG,mEAAmE,CAAC;AAErF,SAAS,GAAG,CAAC,KAAc;IACzB,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/F,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"terminal-token-usage.js","sourceRoot":"","sources":["../src/terminal-token-usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -293,6 +293,28 @@ not cost — a live scripted run drives a real browser against a real running ap
|
|
|
293
293
|
declaration as spend. "Live" on this route must never silently come to mean "costs money";
|
|
294
294
|
this paragraph is the record of that decision.
|
|
295
295
|
|
|
296
|
+
## Optional closing report
|
|
297
|
+
|
|
298
|
+
`CuaProvider.debrief` is an optional read-only request after a structured
|
|
299
|
+
`stopWhen` or dwell stop. It returns a `CuaTurn` with `closingReport` containing
|
|
300
|
+
`summary` and `frictionReports`; an empty friction list is valid. The loop rejects
|
|
301
|
+
actions, pending safety checks, and invalid report shapes. It redacts accepted
|
|
302
|
+
reports, records them in `ActorTrace.debrief`, and projects one readable message
|
|
303
|
+
without invoking action or communication callbacks.
|
|
304
|
+
|
|
305
|
+
This request uses the final observation and retained provider history. It does
|
|
306
|
+
not expose the hidden stop criterion or change the original task outcome. It is
|
|
307
|
+
skipped before any participant turn, after natural completion, without provider
|
|
308
|
+
support, or without remaining time and known budget. An attempted request's
|
|
309
|
+
unreported usage remains an unknown cost line. `counts.debriefCalls` is separate
|
|
310
|
+
from interaction turns, and reported usage contributes to aggregate cost.
|
|
311
|
+
|
|
312
|
+
The OpenAI implementation makes one request with tools disabled and structured
|
|
313
|
+
output; no HTTP or policy retries. Stateless/ZDR mode does not offer retrospective
|
|
314
|
+
reporting because it does not retain the required session history. The
|
|
315
|
+
[paired live receipt](../goals/computer-use-actor/receipts/structured-closing-report-2026-09-05.md)
|
|
316
|
+
records both report recovery and control failures in the separate legacy parser.
|
|
317
|
+
|
|
296
318
|
## The state-driven executor seam (shipped — the transport-agnostic intent, made real)
|
|
297
319
|
|
|
298
320
|
The `CuaExecutor` / `CuaProvider` ports are the concrete realization of the "plural harnesses /
|
|
@@ -28,7 +28,7 @@ This is the "plural harnesses / transport-agnostic" intent of
|
|
|
28
28
|
```ts
|
|
29
29
|
interface CuaExecutor {
|
|
30
30
|
observe(): Promise<CuaObservation>; // capture current state
|
|
31
|
-
execute(action: CuaAction): Promise<void>; // perform one action
|
|
31
|
+
execute(action: CuaAction, signal?: AbortSignal): Promise<void>; // perform one action
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
interface CuaObservation {
|
|
@@ -38,6 +38,15 @@ interface CuaObservation {
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
The loop aborts an action's optional signal when its wait ends, including cancellation or a
|
|
42
|
+
deadline. An executor that prepares asynchronously should check the signal before dispatching
|
|
43
|
+
an input; wrappers must forward it (`execute: (...args) => inner.execute(...args)`). Existing
|
|
44
|
+
one-argument executors remain compatible. This does not cancel already-dispatched substrate
|
|
45
|
+
operations. The desktop executor uses this boundary while reading the current cursor before
|
|
46
|
+
left/double clicks: an exact integer match avoids redundant movement; uncertain or fractional
|
|
47
|
+
coordinates retain the original SDK path. The cursor read adds at most 500 ms of preparation
|
|
48
|
+
wait and does not cache a previous action's position.
|
|
49
|
+
|
|
41
50
|
- **`screenshot` is optional.** A non-vision (state) executor omits it. The loop
|
|
42
51
|
persists no screenshot that turn; `counts.screenshots` stays 0, so the trace's
|
|
43
52
|
`redaction.screenshots` resolves to `"n/a"`. No fabricated `Buffer.alloc(0)`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Terminal-product real-agent lane (issue #154)
|
|
2
2
|
|
|
3
|
-
Date: 2026-06-16 (
|
|
3
|
+
Date: 2026-06-16 (runtime-auth contract updated 2026-09-05)
|
|
4
4
|
|
|
5
5
|
Status: live terminal-product route shipped in `0.8.0`. The in-sandbox backend,
|
|
6
6
|
command-scoped credential placement, exact-id cleanup proof, an interventions ledger,
|
|
@@ -16,8 +16,8 @@ for the full slice plan and the safety contract.
|
|
|
16
16
|
|
|
17
17
|
A lab lane for **terminal-product real-agent studies**: a real autonomous coding
|
|
18
18
|
agent (Codex) discovering and using a CLI/product from its **public surfaces
|
|
19
|
-
only**, running **inside an E2B shell** with
|
|
20
|
-
|
|
19
|
+
only**, running **inside an E2B shell** with declared runtime-auth placement and
|
|
20
|
+
spend/time caps, emitting durable terminal/substrate/cost/no-spend/cleanup/
|
|
21
21
|
intervention proof that verifies fail-closed. This is distinct from the browser
|
|
22
22
|
lanes: it is not testing whether a browser can click a local web app — it tests
|
|
23
23
|
whether an autonomous agent can discover and use a CLI/product surface from
|
|
@@ -36,7 +36,9 @@ fail-closed cross-validation, and forward-declared warnings.
|
|
|
36
36
|
| `subject.product` | `{ name, publicSurfaces[] }` — the only world the agent sees |
|
|
37
37
|
| `execution.target` | `e2b-terminal` (or absent → implied) |
|
|
38
38
|
| `execution.terminal` | `{ transport: exec-stream, stdin: disabled }` |
|
|
39
|
-
| `execution.runtimeAuth` | `openai-env` (names-only durable evidence
|
|
39
|
+
| `execution.runtimeAuth` | `openai-env` (default) or opt-in `openai-egress`; names-only durable evidence |
|
|
40
|
+
| `execution.runtime.version` | Optional exact `@openai/codex` version; observed before keyed execution |
|
|
41
|
+
| `actors[0].model` / `reasoningEffort` | Forwarded to Codex; retained as declarations, not observed provider identity |
|
|
40
42
|
| `scenario.caps` | `{ maxUsd, maxJobs, maxMinutes }` — the blast-radius budget |
|
|
41
43
|
| `policies` | `allowPrivateRepoAccess` / `allowProviderCredentials` / `allowPaymentCredentials` / `allowGitHubMutation`, all DEFAULT FALSE |
|
|
42
44
|
| `actors[0].type` | `codex-exec` — a registered terminal actor (`keyPlacement: in-sandbox-command-scoped`) |
|
|
@@ -46,9 +48,143 @@ Routing is `routesToTerminalProduct(config)` — the single source of truth that
|
|
|
46
48
|
both `selectLabBackend` and the forward-declared-warning logic consume, mirroring
|
|
47
49
|
`routesToComputerUse` / `routesToScriptedBrowser`.
|
|
48
50
|
|
|
49
|
-
##
|
|
51
|
+
## Repeating a terminal study with the same runtime
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
```yaml
|
|
54
|
+
actors:
|
|
55
|
+
- type: codex-exec
|
|
56
|
+
model: gpt-5.6-sol
|
|
57
|
+
reasoningEffort: low
|
|
58
|
+
execution:
|
|
59
|
+
target: e2b-terminal
|
|
60
|
+
runtime:
|
|
61
|
+
version: 0.153.3
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
An explicit version must be exact semver; tags, ranges, URLs, and extra runtime
|
|
65
|
+
fields fail at parsing. Before the keyed actor command, Humanish runs an unkeyed
|
|
66
|
+
`npx @openai/codex@<selector> --version` command with a 60-second deadline.
|
|
67
|
+
A malformed result, nonzero exit, or requested/observed mismatch fails the lane
|
|
68
|
+
and reclaims its owned sandbox. When the version is omitted, the probe resolves
|
|
69
|
+
`latest` once and execution uses the exact version it reported.
|
|
70
|
+
|
|
71
|
+
`actor.json`, the bundle's terminal actor, and `terminal-ledgers.json` retain
|
|
72
|
+
`humanish.actor-runtime.v1`: requested and observed versions, verification status,
|
|
73
|
+
declared model/effort, and the usage granularity. The observed executable version
|
|
74
|
+
also appears as `providerVersion`. An undeclared model stays explicitly
|
|
75
|
+
`runtime_default_unobserved`; Humanish does not label the runtime name as a model.
|
|
76
|
+
Dry runs record declarations only, in a `terminal-lab.runtime.declared` event.
|
|
77
|
+
|
|
78
|
+
These settings make a study's request reproducible, but do not attest the actual
|
|
79
|
+
provider model or add a provider spending limit. Codex `turn.completed` usage can
|
|
80
|
+
aggregate several model requests, so Humanish does not use a declared model to
|
|
81
|
+
infer per-request pricing tiers or fill in unknown costs. Runtime-token costs
|
|
82
|
+
and the studied product's no-spend boundary still need separate interpretation.
|
|
83
|
+
|
|
84
|
+
## Runtime auth: raw-key placement and remaining provider access
|
|
85
|
+
|
|
86
|
+
`execution.runtimeAuth: openai-env` remains the compatible default. It supplies
|
|
87
|
+
`CODEX_API_KEY` command-scoped to Codex, with `OPENAI_API_KEY` also supplied when
|
|
88
|
+
that was the host source. Child processes can read and use the raw key.
|
|
89
|
+
|
|
90
|
+
Opt in to keeping the raw key outside the sandbox:
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
execution:
|
|
94
|
+
target: e2b-terminal
|
|
95
|
+
runtimeAuth: openai-egress
|
|
96
|
+
terminal:
|
|
97
|
+
transport: exec-stream
|
|
98
|
+
stdin: disabled
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`openai-egress` resolves the same host key (`CODEX_API_KEY` first, otherwise
|
|
102
|
+
`OPENAI_API_KEY`) and supplies it only to E2B's host-side network rule for
|
|
103
|
+
`api.openai.com`. The rule sets the HTTPS `Authorization` header. The sandbox's
|
|
104
|
+
Codex command receives the nonsecret value `humanish-egress-auth-placeholder`
|
|
105
|
+
under `CODEX_API_KEY`, plus `CODEX_CA_CERTIFICATE` pointing at E2B's existing
|
|
106
|
+
system CA bundle (`/etc/ssl/certs/ca-certificates.crt`) so TLS verification trusts
|
|
107
|
+
the platform's proxy CA. Humanish does not disable TLS verification or download
|
|
108
|
+
an unauthenticated CA. The sandbox receives no raw runtime key in command env, sandbox env,
|
|
109
|
+
files, metadata, or captured evidence. The host still scrubs the actual key from
|
|
110
|
+
output and errors, including errors during sandbox creation.
|
|
111
|
+
|
|
112
|
+
This mode supports the default OpenAI endpoint only. Humanish explicitly sets
|
|
113
|
+
Codex's built-in `openai` provider and `openai_base_url` to
|
|
114
|
+
`https://api.openai.com/v1` for that invocation. It does not support a custom
|
|
115
|
+
provider, proxy base URL, or regional endpoint under this mode. `openai-env`
|
|
116
|
+
retains its existing command behavior. E2B header rules are a public-beta
|
|
117
|
+
capability; the local contract is checked against the installed Desktop SDK
|
|
118
|
+
(`@e2b/desktop` 2.3.3, resolving `e2b` 2.46.1).
|
|
119
|
+
|
|
120
|
+
**The sandbox still has a spendable OpenAI proxy capability.** Every process can
|
|
121
|
+
make authenticated requests to that host from sandbox creation until teardown,
|
|
122
|
+
including bootstrap/setup commands and commands launched outside Codex. Calls
|
|
123
|
+
made outside Codex may be absent from its usage ledger. This mode does not impose
|
|
124
|
+
a provider-side spending limit, restrict models/API paths, or make
|
|
125
|
+
`scenario.caps.maxUsd` a preventive provider budget. A hard provider budget needs
|
|
126
|
+
a separately enforced control; do not infer zero spend from an unmeasured ledger
|
|
127
|
+
line.
|
|
128
|
+
|
|
129
|
+
Public internet discovery stays unrestricted unless the lab already declares
|
|
130
|
+
`execution.egressAllow`. The mode preserves that allowlist and its deny-all
|
|
131
|
+
fallback without adding hosts. If an allowlist omits `api.openai.com`, provider
|
|
132
|
+
requests can fail. E2B domain allowlists are routing controls rather than strict
|
|
133
|
+
destination isolation on shared infrastructure. An existing exact OpenAI host
|
|
134
|
+
rule is rejected instead of silently overwritten.
|
|
135
|
+
|
|
136
|
+
Evidence records the selected auth mode and the residual proxy capability.
|
|
137
|
+
Resolved live actor traces use `keyPlacement: external` in `openai-egress`; the
|
|
138
|
+
actor registry continues to describe the default `in-sandbox-command-scoped`
|
|
139
|
+
placement. Dry runs record declarations and prove no live proxy behavior.
|
|
140
|
+
|
|
141
|
+
The upstream contracts are documented in [E2B internet access and network
|
|
142
|
+
rules](https://docs.e2b.dev/network/internet-access) and [Codex advanced
|
|
143
|
+
configuration](https://developers.openai.com/codex/config-advanced),
|
|
144
|
+
[Codex custom CA bundles](https://developers.openai.com/codex/auth#custom-ca-bundles),
|
|
145
|
+
and [E2B's CA installer](https://github.com/e2b-dev/infra/blob/main/packages/envd/internal/host/cacerts.go).
|
|
146
|
+
E2B's installed
|
|
147
|
+
SDK documents that transformed headers override request headers. Deterministic
|
|
148
|
+
request/redaction tests do not establish live wire behavior. The [2026-09-05
|
|
149
|
+
transport receipt](../goals/terminal-product-lane/receipts/2026-09-05-runtime-egress-auth.md)
|
|
150
|
+
records the controlled live header/auth checks and their scope.
|
|
151
|
+
|
|
152
|
+
## Runtime prerequisite
|
|
153
|
+
|
|
154
|
+
The terminal route reuses a working Node >=20 and npm from the calling shell.
|
|
155
|
+
Otherwise it installs the pinned official Node 22.23.2 Linux x64 or arm64 archive,
|
|
156
|
+
downloaded over verified HTTPS and checked against an architecture-specific
|
|
157
|
+
SHA256 committed in the bootstrap. It does not refresh apt repositories or fetch
|
|
158
|
+
an unpinned checksum beside the archive. Node 22 is a supported LTS line on the
|
|
159
|
+
[official release schedule](https://nodejs.org/en/about/previous-releases); the
|
|
160
|
+
trusted hashes come from its [release manifest](https://nodejs.org/dist/v22.23.2/SHASUMS256.txt).
|
|
161
|
+
|
|
162
|
+
Installation requires `curl`, `sha256sum`, `tar`, `gzip`, `mktemp`, and passwordless
|
|
163
|
+
`sudo`. Only a verified archive is extracted into a root-owned versioned directory
|
|
164
|
+
under `/opt/humanish`; `/usr/local/bin` links make Node/npm/npx available to later
|
|
165
|
+
shells. In that new distribution only, a missing built-in npm `prefix` defaults
|
|
166
|
+
to `/usr/local`, so global product executables use the existing PATH. Existing
|
|
167
|
+
distribution settings and higher-priority npm overrides are preserved; an adopter
|
|
168
|
+
override can still choose a bin directory outside PATH. The installer changes no
|
|
169
|
+
user/global npm configuration, global permissions, or shell startup files. It
|
|
170
|
+
checks Node/npm in both ordinary and sudo shells after installation. The existing
|
|
171
|
+
runtime fast path preserves user-specific installations; a later sudo product
|
|
172
|
+
install can still fail if that installation is absent from sudo's PATH.
|
|
173
|
+
|
|
174
|
+
The [global executable receipt](../goals/terminal-product-lane/receipts/2026-09-05-global-npm-prefix.md)
|
|
175
|
+
records the regression found after the initial runtime-only proof and its stock
|
|
176
|
+
desktop checks. npm documents [global executable locations](https://docs.npmjs.com/cli/v10/configuring-npm/folders#executables)
|
|
177
|
+
and the [distribution built-in configuration](https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#built-in-config-file).
|
|
178
|
+
|
|
179
|
+
An egress allowlist must permit `nodejs.org` if the runtime needs installation,
|
|
180
|
+
as well as the registries and product surfaces the study uses. Missing tools,
|
|
181
|
+
unsupported architectures, a failed download or checksum, and a failed runtime
|
|
182
|
+
check stop the lane before Codex. Downloads have finite connection, transfer, and
|
|
183
|
+
retry bounds within the existing five-minute bootstrap deadline.
|
|
184
|
+
|
|
185
|
+
## The original command-scoped safety contract
|
|
186
|
+
|
|
187
|
+
The default mode **inverts** the credential-placement default of every other E2B route.
|
|
52
188
|
On the computer-use route the model's key stays *outside* the sandbox; here the
|
|
53
189
|
agent-under-test runs *inside* with a real `OPENAI_API_KEY`/`CODEX_API_KEY` and
|
|
54
190
|
is **presumed exfiltratable**. The doctrine (invariants-and-defaults.md, the
|
|
@@ -52,6 +52,20 @@ setup-quality gap, ceremonial/absent study quality, target-app blocker, or
|
|
|
52
52
|
Humanish CLI blocker. The OSS
|
|
53
53
|
meta-lab is one maintainer dogfood example, not the only candidate source.
|
|
54
54
|
|
|
55
|
+
For completed computer-use sessions, participant-reported friction comes from
|
|
56
|
+
the redacted closing report and observed-report clauses in earlier messages.
|
|
57
|
+
Matching `stopWhen` or ending a dwell window does not discard an earlier
|
|
58
|
+
report or change the successful completion verdict. Exact repeated reports
|
|
59
|
+
appear once in the lane's candidate. Harness notices, reasoning, and observed
|
|
60
|
+
page content do not become participant findings; quoted app copy and negated
|
|
61
|
+
reports retain the existing exclusions. Code excerpts are treated as quoted
|
|
62
|
+
material. Interim matching requires an observation-shaped clause and filters
|
|
63
|
+
common plans, questions, and hypotheticals; a report followed by a retry plan
|
|
64
|
+
can still qualify. This text
|
|
65
|
+
heuristic does not establish that a reported defect is real or independently
|
|
66
|
+
confirmed. A custom session's closing `reason` remains eligible even when it
|
|
67
|
+
was not repeated in the message trace.
|
|
68
|
+
|
|
55
69
|
### `draft`
|
|
56
70
|
|
|
57
71
|
Builds structured feedback from the strongest run candidate first. If no
|
|
@@ -126,7 +126,11 @@ enters this field; identity is digests, a sha, a boolean, and counts.
|
|
|
126
126
|
|
|
127
127
|
`cost` is optional and additive (`humanish.run-cost-summary.v1`): the
|
|
128
128
|
computer-use lane's run-level cost ESTIMATE — the sum of each lane's
|
|
129
|
-
token-derived model cost plus
|
|
129
|
+
token-derived model cost plus E2B desktop compute lines. New independent CUA runs
|
|
130
|
+
emit one line per owned desktop, keyed by public lane ID and carrying observed CPU/memory,
|
|
131
|
+
resource source, host-measured minutes, and the derived per-second rate. Older
|
|
132
|
+
single aggregate desktop lines remain valid. Missing resource metadata stays
|
|
133
|
+
unpriced; unconfirmed cleanup adds an unknown remaining-lifetime line. It is an
|
|
130
134
|
ESTIMATE, never authoritative: every dollar is a rate-table multiply from the
|
|
131
135
|
operator-editable `src/pricing.ts`, carries the pricing `ratesAsOf` date and
|
|
132
136
|
`source`, and is surfaced with the "estimated (rates as of `<date>`)" label —
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Date: 2026-06-02 (current-state note updated 2026-07-14)
|
|
4
4
|
|
|
5
5
|
Status: reference map for the major contracts shipped through source version
|
|
6
|
-
`0.
|
|
6
|
+
`0.82.0`; it is not an exhaustive inventory of command/result envelopes. Exported types,
|
|
7
7
|
schema constants, parsers, and validators in `src/` are authoritative. Rows
|
|
8
8
|
marked "reserved" name layering intent only — no code emits or validates them
|
|
9
9
|
yet. Do not emit a reserved schema.
|
|
@@ -978,16 +978,16 @@ never authoritative: every dollar figure is a rate-table multiply, labeled
|
|
|
978
978
|
`humanish.run-bundle.v1` stays v1 and every pre-existing bundle is byte-stable:
|
|
979
979
|
|
|
980
980
|
- `humanish.pricing.v1` — the OPERATOR-EDITABLE rate table in `src/pricing.ts`:
|
|
981
|
-
dated per-model input/output USD-per-token rates and
|
|
982
|
-
|
|
981
|
+
dated per-model input/output USD-per-token rates and E2B CPU/GiB-second
|
|
982
|
+
rates, each with a public pricing-page `source` and an `asOf`
|
|
983
983
|
date. A prominent banner says these are estimates to update when providers
|
|
984
984
|
change pricing. Model rates may carry a `cacheWriteUsdPerToken` (OpenAI 5.6+
|
|
985
985
|
bills cache writes at 1.25x input as the total rate for written tokens) and a
|
|
986
986
|
`longContext` tier (a per-request input threshold that re-prices the whole
|
|
987
987
|
request; priced exactly only from the trace's per-request `turns` ledger —
|
|
988
988
|
totals alone never re-tier, which is the under-estimate direction). Some
|
|
989
|
-
entries are `placeholder: true` stand-ins (the
|
|
990
|
-
|
|
989
|
+
entries are `placeholder: true` stand-ins (the legacy desktop helper's
|
|
990
|
+
8-vCPU/8-GiB planning assumption) — an operator MUST confirm them before trusting
|
|
991
991
|
the magnitude; the flag propagates into every estimate so a stand-in is never
|
|
992
992
|
mistaken for a live rate. An UNKNOWN model/desktop rate is DECLARED ABSENT
|
|
993
993
|
(`estimatedCostUsd: null` + a `reason`), never guessed.
|
|
@@ -996,7 +996,14 @@ never authoritative: every dollar figure is a rate-table multiply, labeled
|
|
|
996
996
|
`no_rate_for_model`/`no_token_usage`), `ratesAsOf`, `source`, `modelId`,
|
|
997
997
|
optional `placeholder`, and a `breakdown`.
|
|
998
998
|
- `humanish.run-cost-summary.v1` — `RunBundle.cost`: the sum of every lane's
|
|
999
|
-
`model-tokens`
|
|
999
|
+
`model-tokens` lines PLUS `desktop-minutes` lines. New independent CUA runs
|
|
1000
|
+
price each owned desktop separately; older single aggregate lines remain readable.
|
|
1001
|
+
A desktop line's optional `desktop` object records `minutes`,
|
|
1002
|
+
`durationBasis: host-acquired-to-cleanup`, observed `resources` (`cpuCount`,
|
|
1003
|
+
`memoryMiB`), `resourceSource: e2b.getInfo`, and `usdPerSecond` when priceable.
|
|
1004
|
+
Failed metadata reads record `resourceUnavailableReason`; no resource guess is used.
|
|
1005
|
+
Resource metadata and missing/unsupported rates produce a null line. A kept or
|
|
1006
|
+
unconfirmed allocation adds `desktop_lifetime_incomplete` as a second null line.
|
|
1000
1007
|
|
|
1001
1008
|
The summary follows the SAME null discipline as the terminal cost ledger above.
|
|
1002
1009
|
`estimatedTotalUsd` sums ONLY the non-null `breakdown` lines and is `null` iff
|
|
@@ -1008,8 +1015,10 @@ tried and could not price it) and contributes nothing. `fullyEstimated` is
|
|
|
1008
1015
|
the MIN (oldest) `asOf` across contributing rates — an aggregate is only as fresh
|
|
1009
1016
|
as its stalest input, so MAX would overclaim freshness (each `breakdown` line
|
|
1010
1017
|
keeps its own true `asOf`). `desktopMinutes` is a HOST-SIDE
|
|
1011
|
-
|
|
1012
|
-
|
|
1018
|
+
acquired-handle→cleanup span, excluding allocation/startup before handle acquisition.
|
|
1019
|
+
It approximates E2B's server-side billed lifetime. Plan fees, credits, and negotiated
|
|
1020
|
+
prices are excluded; unknown remaining lifetime makes `fullyEstimated` false.
|
|
1021
|
+
Shared-world, scripted-browser, and terminal routes do not yet emit these desktop lines.
|
|
1013
1022
|
|
|
1014
1023
|
```yaml
|
|
1015
1024
|
schema: humanish.run-cost-summary.v1
|