@openclaw/lobster 2026.9.5 → 2026.9.7
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/assets/icon.png +0 -0
- package/dist/index.js +8 -294
- package/node_modules/@clawdbot/lobster/README.md +20 -133
- package/node_modules/@clawdbot/lobster/VISION.md +15 -238
- package/node_modules/@clawdbot/lobster/bin/clawd.invoke.js +2 -21
- package/node_modules/@clawdbot/lobster/bin/invoke.js +19 -0
- package/node_modules/@clawdbot/lobster/bin/lobster.js +2 -21
- package/node_modules/@clawdbot/lobster/bin/openclaw.invoke.js +2 -24
- package/node_modules/@clawdbot/lobster/dist/src/cli.js +32 -48
- package/node_modules/@clawdbot/lobster/dist/src/cli.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/command_tokens.js +81 -0
- package/node_modules/@clawdbot/lobster/dist/src/command_tokens.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/dedupe.js +1 -12
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/dedupe.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/group_by.js +2 -14
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/group_by.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/llm_invoke.js +1 -337
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/llm_invoke.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/map.js +2 -13
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/map.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/sort.js +4 -21
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/sort.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/state.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/state.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/template.js +2 -13
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/template.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_run.js +0 -18
- package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_run.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/core/llm_accounting.js +304 -0
- package/node_modules/@clawdbot/lobster/dist/src/core/llm_accounting.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/core/value_path.js +11 -0
- package/node_modules/@clawdbot/lobster/dist/src/core/value_path.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/parser.js +2 -67
- package/node_modules/@clawdbot/lobster/dist/src/parser.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/index.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/pr-monitor.js +5 -64
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/pr-monitor.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/read_pr.js +45 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/read_pr.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/snapshot.js +45 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/snapshot.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/stages/pr-view.js +9 -47
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/stages/pr-view.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/Lobster.js +18 -135
- package/node_modules/@clawdbot/lobster/dist/src/sdk/Lobster.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/index.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/approve.js +1 -2
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/approve.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/diff.js +2 -8
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/diff.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/exec.js +15 -81
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/exec.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/state.js +3 -9
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/state.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/runtime.js +0 -12
- package/node_modules/@clawdbot/lobster/dist/src/sdk/runtime.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/state_env.js +6 -0
- package/node_modules/@clawdbot/lobster/dist/src/sdk/state_env.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/state/atomic_file.js +192 -0
- package/node_modules/@clawdbot/lobster/dist/src/state/atomic_file.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/state/store.js +2 -188
- package/node_modules/@clawdbot/lobster/dist/src/state/store.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/dry_run.js +262 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/dry_run.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/expressions.js +345 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/expressions.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/file.js +21 -1036
- package/node_modules/@clawdbot/lobster/dist/src/workflows/file.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/github_pr_monitor.js +8 -77
- package/node_modules/@clawdbot/lobster/dist/src/workflows/github_pr_monitor.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/graph.js +1 -7
- package/node_modules/@clawdbot/lobster/dist/src/workflows/graph.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/load.js +347 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/load.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/types.js +2 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/types.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/values.js +93 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/values.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/cancellation.test.js +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/cancellation.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/cli_run_errors.test.js +53 -0
- package/node_modules/@clawdbot/lobster/dist/test/cli_run_errors.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/command_arguments.test.js +82 -0
- package/node_modules/@clawdbot/lobster/dist/test/command_arguments.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/cost_tracker.test.js +49 -19
- package/node_modules/@clawdbot/lobster/dist/test/cost_tracker.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/helpers/node_shell_fixture.js +17 -0
- package/node_modules/@clawdbot/lobster/dist/test/helpers/node_shell_fixture.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/llm_invoke.test.js +2 -0
- package/node_modules/@clawdbot/lobster/dist/test/llm_invoke.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/pipeline_resume_state.test.js +65 -0
- package/node_modules/@clawdbot/lobster/dist/test/pipeline_resume_state.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/process_output_limit.test.js +5 -3
- package/node_modules/@clawdbot/lobster/dist/test/process_output_limit.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/sdk_exec.test.js +72 -25
- package/node_modules/@clawdbot/lobster/dist/test/sdk_exec.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflow_graph.test.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflow_graph.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/README.md +1 -0
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/SECURITY.md +62 -13
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/index.js +40 -9
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/lib/schemes.js +76 -16
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/lib/utils.js +54 -10
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/package.json +1 -1
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/fixtures/uri-js-parse.json +1 -0
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/ipv6-validation.test.js +130 -0
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/mailto-authority-security.test.js +125 -0
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/mailto-field-name-security.test.js +151 -0
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/security-normalization.test.js +38 -0
- package/node_modules/@clawdbot/lobster/node_modules/fast-uri/types/index.d.ts +16 -0
- package/node_modules/@clawdbot/lobster/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/@clawdbot/lobster/node_modules/yaml/browser/dist/nodes/Alias.js +25 -23
- package/node_modules/@clawdbot/lobster/node_modules/yaml/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/@clawdbot/lobster/node_modules/yaml/dist/nodes/Alias.js +25 -23
- package/node_modules/@clawdbot/lobster/node_modules/yaml/package.json +1 -1
- package/node_modules/@clawdbot/lobster/package.json +6 -8
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/package.json +6 -6
- package/dist/runtime-api.js +0 -3
- package/node_modules/@clawdbot/lobster/dist/src/sdk/token.js +0 -9
- package/node_modules/@clawdbot/lobster/dist/src/sdk/token.js.map +0 -1
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
for (const kind of ["missing", "directory", "extension"]) {
|
|
8
|
+
test(`tool run reports ${kind} workflow target errors as JSON`, async () => {
|
|
9
|
+
const dir = await mkdtemp(join(tmpdir(), "lobster-target-error-"));
|
|
10
|
+
try {
|
|
11
|
+
const target = kind === "directory"
|
|
12
|
+
? dir
|
|
13
|
+
: join(dir, kind === "extension" ? "workflow.txt" : "missing.lobster");
|
|
14
|
+
if (kind === "extension")
|
|
15
|
+
await writeFile(target, JSON.stringify({ steps: [{ id: "ok", run: "echo ok" }] }));
|
|
16
|
+
const result = spawnSync(process.execPath, ["bin/lobster.js", "run", "--mode", "tool", "--file", target], { encoding: "utf8" });
|
|
17
|
+
assert.equal(result.status, 2);
|
|
18
|
+
const envelope = JSON.parse(result.stdout);
|
|
19
|
+
assert.equal(envelope.protocolVersion, 1);
|
|
20
|
+
assert.equal(envelope.ok, false);
|
|
21
|
+
assert.equal(envelope.error.type, "parse_error");
|
|
22
|
+
assert.match(envelope.error.message, kind === "missing" ? /ENOENT/ : kind === "directory" ? /not a file/ : /must end in/);
|
|
23
|
+
assert.equal(result.stderr, "");
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
await rm(dir, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
test("human run reports missing workflow without an uncaught stack", async () => {
|
|
31
|
+
const dir = await mkdtemp(join(tmpdir(), "lobster-human-error-"));
|
|
32
|
+
try {
|
|
33
|
+
const result = spawnSync(process.execPath, ["bin/lobster.js", "run", "--file", join(dir, "missing.json")], { encoding: "utf8" });
|
|
34
|
+
assert.equal(result.status, 2);
|
|
35
|
+
assert.equal(result.stdout, "");
|
|
36
|
+
assert.match(result.stderr, /^Parse error: .*ENOENT/);
|
|
37
|
+
assert.doesNotMatch(result.stderr, /at async|node:internal/);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
await rm(dir, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
for (const flag of ["--help", "-h"]) {
|
|
44
|
+
test(`graph ${flag} shows graph-specific options`, () => {
|
|
45
|
+
const result = spawnSync(process.execPath, ["bin/lobster.js", "graph", flag], {
|
|
46
|
+
encoding: "utf8",
|
|
47
|
+
});
|
|
48
|
+
assert.equal(result.status, 0);
|
|
49
|
+
assert.match(result.stdout, /--format\s+Output format: mermaid \(default\), dot, ascii/);
|
|
50
|
+
assert.equal(result.stderr, "");
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=cli_run_errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli_run_errors.test.js","sourceRoot":"","sources":["../../test/cli_run_errors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { parsePipeline } from "../src/parser.js";
|
|
7
|
+
import { Lobster, exec } from "../src/sdk/index.js";
|
|
8
|
+
const runFile = promisify(execFile);
|
|
9
|
+
const argvScript = "console.log(JSON.stringify(process.argv.slice(1)))";
|
|
10
|
+
const argvCommand = `${JSON.stringify(process.execPath)} -e '${argvScript}' "" tail`;
|
|
11
|
+
test("pipeline parsing preserves empty positional arguments", () => {
|
|
12
|
+
assert.deepEqual(parsePipeline(`exec node "" ' ' '' tail`)[0].args._, [
|
|
13
|
+
"node",
|
|
14
|
+
"",
|
|
15
|
+
" ",
|
|
16
|
+
"",
|
|
17
|
+
"tail",
|
|
18
|
+
]);
|
|
19
|
+
});
|
|
20
|
+
test("pipeline parsing preserves an empty quoted option value", () => {
|
|
21
|
+
const args = parsePipeline(`custom --value "" tail`)[0].args;
|
|
22
|
+
assert.equal(args["value"], "");
|
|
23
|
+
assert.deepEqual(args._, ["tail"]);
|
|
24
|
+
});
|
|
25
|
+
test("built CLI passes explicit empty arguments to a child process", async () => {
|
|
26
|
+
const { stdout } = await runFile(process.execPath, [
|
|
27
|
+
"bin/lobster.js",
|
|
28
|
+
"run",
|
|
29
|
+
"--mode",
|
|
30
|
+
"tool",
|
|
31
|
+
`exec --json ${argvCommand}`,
|
|
32
|
+
]);
|
|
33
|
+
assert.deepEqual(JSON.parse(stdout).output, ["", "tail"]);
|
|
34
|
+
});
|
|
35
|
+
test("SDK exec passes explicit empty arguments to a child process", async () => {
|
|
36
|
+
const result = await new Lobster().pipe(exec(argvCommand)).run();
|
|
37
|
+
assert.equal(result.ok, true, JSON.stringify(result));
|
|
38
|
+
assert.deepEqual(result.output, ["", "tail"]);
|
|
39
|
+
});
|
|
40
|
+
for (const alias of ["openclaw.invoke", "clawd.invoke"]) {
|
|
41
|
+
test(`${alias} shim preserves punctuation and literal pipeline characters`, async () => {
|
|
42
|
+
const expected = {
|
|
43
|
+
text: 'O\'Malley says "hello"\nnext line',
|
|
44
|
+
path: "C:\\folder\\",
|
|
45
|
+
literal: "$HOME `id` | head",
|
|
46
|
+
empty: "",
|
|
47
|
+
};
|
|
48
|
+
const requests = [];
|
|
49
|
+
const server = createServer(async (req, res) => {
|
|
50
|
+
let body = "";
|
|
51
|
+
for await (const chunk of req)
|
|
52
|
+
body += chunk;
|
|
53
|
+
const payload = JSON.parse(body);
|
|
54
|
+
requests.push(payload.args);
|
|
55
|
+
res.setHeader("content-type", "application/json");
|
|
56
|
+
res.end(JSON.stringify({ ok: true, result: [payload.args] }));
|
|
57
|
+
});
|
|
58
|
+
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
59
|
+
try {
|
|
60
|
+
const address = server.address();
|
|
61
|
+
assert.ok(address && typeof address === "object");
|
|
62
|
+
const { stdout } = await runFile(process.execPath, [
|
|
63
|
+
`bin/${alias}.js`,
|
|
64
|
+
"--url",
|
|
65
|
+
`http://127.0.0.1:${address.port}`,
|
|
66
|
+
"--tool",
|
|
67
|
+
"proof",
|
|
68
|
+
"--action",
|
|
69
|
+
"read",
|
|
70
|
+
"--args-json",
|
|
71
|
+
JSON.stringify(expected),
|
|
72
|
+
], { env: { ...process.env, OPENCLAW_TOKEN: "", CLAWD_TOKEN: "" } });
|
|
73
|
+
assert.deepEqual(JSON.parse(stdout), [expected]);
|
|
74
|
+
assert.deepEqual(requests, [expected]);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
server.closeAllConnections();
|
|
78
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=command_arguments.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command_arguments.test.js","sourceRoot":"","sources":["../../test/command_arguments.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { PassThrough } from "node:stream";
|
|
8
8
|
import { createDefaultRegistry } from "../src/commands/registry.js";
|
|
9
9
|
import { CostTracker } from "../src/core/cost_tracker.js";
|
|
10
|
-
import { createLlmSpendLedger, llmProvenanceOf, restoreLlmProvenance, } from "../src/
|
|
10
|
+
import { createLlmSpendLedger, llmProvenanceOf, restoreLlmProvenance, } from "../src/core/llm_accounting.js";
|
|
11
11
|
import { runWorkflowFile } from "../src/workflows/file.js";
|
|
12
12
|
import { decodeToken } from "../src/token.js";
|
|
13
13
|
test("CostTracker records usage and computes totals", () => {
|
|
@@ -121,19 +121,25 @@ async function runWorkflow(workflow, envOverride, llmAdapters) {
|
|
|
121
121
|
stderr.on("data", (d) => {
|
|
122
122
|
stderrOutput += String(d);
|
|
123
123
|
});
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
124
|
+
try {
|
|
125
|
+
const result = await runWorkflowFile({
|
|
126
|
+
filePath,
|
|
127
|
+
ctx: {
|
|
128
|
+
stdin: process.stdin,
|
|
129
|
+
stdout: process.stdout,
|
|
130
|
+
stderr,
|
|
131
|
+
env: { ...process.env, LOBSTER_STATE_DIR: stateDir, ...envOverride },
|
|
132
|
+
mode: "tool",
|
|
133
|
+
registry: createDefaultRegistry(),
|
|
134
|
+
llmAdapters,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
return { result, stderrOutput };
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
stderr.destroy();
|
|
141
|
+
await fsp.rm(tmpDir, { recursive: true, force: true });
|
|
142
|
+
}
|
|
137
143
|
}
|
|
138
144
|
test("workflow result includes _meta.cost when usage is present", async () => {
|
|
139
145
|
const { result } = await runWorkflow({
|
|
@@ -920,11 +926,6 @@ test("workflow cost tracking bills both live calls a retried step's replays stan
|
|
|
920
926
|
await fsp.rm(cacheDir, { recursive: true, force: true });
|
|
921
927
|
}
|
|
922
928
|
});
|
|
923
|
-
// A gate pauses a run rather than resetting what it spent. The resume is a different run — a
|
|
924
|
-
// different process, even — so the call made before the gate is only in the paused run's
|
|
925
|
-
// record; if a later step repeats the prompt, it replays and correctly bills nothing. Without
|
|
926
|
-
// carrying that record forward, the provider call before the gate would appear in no total at
|
|
927
|
-
// all, and a `cost_limit` could be walked past one gate at a time.
|
|
928
929
|
// A gate pauses a run, it does not reset what the run has spent. The resume is a separate run
|
|
929
930
|
// with its own accounting, so a call made before the gate lives only in the paused run's
|
|
930
931
|
// record: if a later step repeats the prompt it replays, correctly bills nothing, and the
|
|
@@ -1960,4 +1961,33 @@ for (const loop of [false, true]) {
|
|
|
1960
1961
|
assert.equal(calls, 1, "a downstream failure must not hide paid usage from the retry budget");
|
|
1961
1962
|
});
|
|
1962
1963
|
}
|
|
1964
|
+
for (const rendered of [false, true]) {
|
|
1965
|
+
for (const passthrough of ["head --n 1", "pick usage"]) {
|
|
1966
|
+
test(`uninterrupted workflow does not rebill ${rendered ? "rendered" : "live"} output through ${passthrough}`, async () => {
|
|
1967
|
+
const provider = await startFakeProvider();
|
|
1968
|
+
const cacheDir = await fsp.mkdtemp(path.join(os.tmpdir(), "lobster-cost-step-reference-"));
|
|
1969
|
+
try {
|
|
1970
|
+
const { result } = await runWorkflow({
|
|
1971
|
+
cost_limit: { max_usd: 0.01, action: "stop" },
|
|
1972
|
+
steps: [
|
|
1973
|
+
{
|
|
1974
|
+
id: "live",
|
|
1975
|
+
pipeline: `llm.invoke --model gpt-4o --prompt Summarize${rendered ? " | json" : ""}`,
|
|
1976
|
+
},
|
|
1977
|
+
{ id: "copy", pipeline: passthrough, stdin: "$live.json" },
|
|
1978
|
+
{ id: "again", pipeline: "head --n 1", stdin: "$copy.json" },
|
|
1979
|
+
],
|
|
1980
|
+
}, { OPENCLAW_URL: provider.url, LOBSTER_CACHE_DIR: cacheDir });
|
|
1981
|
+
assert.equal(provider.requests(), 1);
|
|
1982
|
+
assert.equal(result._meta?.cost?.totalInputTokens, 1000);
|
|
1983
|
+
assert.equal(result._meta?.cost?.totalOutputTokens, 500);
|
|
1984
|
+
assert.deepEqual(result._meta?.cost?.byStep.map((entry) => entry.stepId), ["live"]);
|
|
1985
|
+
}
|
|
1986
|
+
finally {
|
|
1987
|
+
await provider.close();
|
|
1988
|
+
await fsp.rm(cacheDir, { recursive: true, force: true });
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1963
1993
|
//# sourceMappingURL=cost_tracker.test.js.map
|