@inflexa-ai/harness 0.42.1 → 0.43.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 +2 -2
- package/dist/agents/conversation-agent.js +5 -1
- package/dist/agents/sandbox/drug-repurposing-agent.js +1 -0
- package/dist/agents/sandbox/shared.d.ts +1 -6
- package/dist/agents/sandbox/shared.js +3 -16
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/app/chat-turn.js +13 -1
- package/dist/config/environment-stores.d.ts +4 -2
- package/dist/contracts/chat-events.d.ts +9 -1
- package/dist/contracts/chat-frame.d.ts +3 -3
- package/dist/contracts/chat-frame.js +8 -3
- package/dist/contracts/chat-parts.d.ts +4 -1
- package/dist/contracts/data-profile.d.ts +4 -6
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/report-blocks.d.ts +1364 -75
- package/dist/contracts/report-blocks.js +221 -29
- package/dist/contracts/report-reference.js +1 -1
- package/dist/contracts/schemas/chat-events.d.ts +13 -0
- package/dist/contracts/schemas/chat-events.js +5 -0
- package/dist/contracts/schemas/chat-parts.d.ts +2 -2
- package/dist/contracts/schemas/index.d.ts +1 -1
- package/dist/contracts/schemas/index.js +1 -1
- package/dist/execution/input-signature.d.ts +7 -13
- package/dist/execution/input-signature.js +0 -0
- package/dist/execution/run-canceler.d.ts +3 -2
- package/dist/execution/run-canceler.js +3 -2
- package/dist/execution/run-event-stream.d.ts +16 -2
- package/dist/execution/run-event-stream.js +54 -3
- package/dist/index.d.ts +1 -8
- package/dist/index.js +5 -16
- package/dist/input-scan/enrich.d.ts +0 -2
- package/dist/input-scan/enrich.js +0 -1
- package/dist/lib/metrics.js +6 -7
- package/dist/lib/otel-spans.d.ts +4 -9
- package/dist/lib/otel-spans.js +3 -8
- package/dist/loop/run-agent.d.ts +4 -2
- package/dist/loop/run-agent.js +38 -23
- package/dist/memory/thread-history.d.ts +1 -1
- package/dist/prompts/report-session.d.ts +1 -1
- package/dist/prompts/report-session.js +17 -0
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +7 -0
- package/dist/provenance/exec-frame.d.ts +1 -1
- package/dist/report-model/authoring-grammar.d.ts +416 -17
- package/dist/report-model/authoring-grammar.js +25 -4
- package/dist/report-model/block-walk.d.ts +20 -4
- package/dist/report-model/block-walk.js +64 -7
- package/dist/report-model/draft-finish.d.ts +6 -2
- package/dist/report-model/draft-finish.js +6 -1
- package/dist/report-model/production-resolver.d.ts +8 -0
- package/dist/report-model/production-resolver.js +1 -1
- package/dist/report-model/validate.d.ts +20 -10
- package/dist/report-model/validate.js +29 -13
- package/dist/report-render/chart-export.d.ts +52 -0
- package/dist/report-render/chart-export.js +192 -0
- package/dist/report-render/chart-presets.d.ts +46 -47
- package/dist/report-render/chart-presets.js +31 -101
- package/dist/report-render/chart-renderers.d.ts +163 -0
- package/dist/report-render/chart-renderers.js +1055 -0
- package/dist/report-render/chart-toolbox.d.ts +124 -0
- package/dist/report-render/chart-toolbox.js +595 -0
- package/dist/report-render/chart.d.ts +60 -27
- package/dist/report-render/chart.js +2323 -524
- package/dist/report-render/design.d.ts +476 -16
- package/dist/report-render/design.js +390 -56
- package/dist/report-render/figures/common.d.ts +321 -0
- package/dist/report-render/figures/common.js +759 -0
- package/dist/report-render/figures/dendrogram.d.ts +36 -0
- package/dist/report-render/figures/dendrogram.js +130 -0
- package/dist/report-render/figures/dense.d.ts +111 -0
- package/dist/report-render/figures/dense.js +204 -0
- package/dist/report-render/figures/dotplot.d.ts +28 -0
- package/dist/report-render/figures/dotplot.js +234 -0
- package/dist/report-render/figures/embedding.d.ts +43 -0
- package/dist/report-render/figures/embedding.js +360 -0
- package/dist/report-render/figures/equal-units.d.ts +101 -0
- package/dist/report-render/figures/equal-units.js +215 -0
- package/dist/report-render/figures/forest.d.ts +20 -0
- package/dist/report-render/figures/forest.js +398 -0
- package/dist/report-render/figures/gsea.d.ts +30 -0
- package/dist/report-render/figures/gsea.js +391 -0
- package/dist/report-render/figures/heatmap.d.ts +40 -0
- package/dist/report-render/figures/heatmap.js +395 -0
- package/dist/report-render/figures/index.d.ts +135 -0
- package/dist/report-render/figures/index.js +100 -0
- package/dist/report-render/figures/km.d.ts +16 -0
- package/dist/report-render/figures/km.js +406 -0
- package/dist/report-render/figures/label-room.d.ts +130 -0
- package/dist/report-render/figures/label-room.js +341 -0
- package/dist/report-render/figures/locuszoom.d.ts +50 -0
- package/dist/report-render/figures/locuszoom.js +675 -0
- package/dist/report-render/figures/lollipop.d.ts +16 -0
- package/dist/report-render/figures/lollipop.js +247 -0
- package/dist/report-render/figures/ma.d.ts +20 -0
- package/dist/report-render/figures/ma.js +114 -0
- package/dist/report-render/figures/manhattan.d.ts +60 -0
- package/dist/report-render/figures/manhattan.js +343 -0
- package/dist/report-render/figures/oncoprint.d.ts +41 -0
- package/dist/report-render/figures/oncoprint.js +420 -0
- package/dist/report-render/figures/pca.d.ts +37 -0
- package/dist/report-render/figures/pca.js +241 -0
- package/dist/report-render/figures/qq.d.ts +30 -0
- package/dist/report-render/figures/qq.js +182 -0
- package/dist/report-render/figures/roc.d.ts +17 -0
- package/dist/report-render/figures/roc.js +116 -0
- package/dist/report-render/figures/sankey.d.ts +48 -0
- package/dist/report-render/figures/sankey.js +353 -0
- package/dist/report-render/figures/upset.d.ts +60 -0
- package/dist/report-render/figures/upset.js +316 -0
- package/dist/report-render/figures/volcano.d.ts +25 -0
- package/dist/report-render/figures/volcano.js +166 -0
- package/dist/report-render/hybrid-svg.d.ts +75 -0
- package/dist/report-render/hybrid-svg.js +504 -0
- package/dist/report-render/number-format.d.ts +19 -0
- package/dist/report-render/number-format.js +25 -1
- package/dist/report-render/page.d.ts +41 -4
- package/dist/report-render/page.js +247 -12
- package/dist/report-render/render.d.ts +13 -4
- package/dist/report-render/render.js +37 -6
- package/dist/report-render/types.d.ts +23 -2
- package/dist/report-render/value-bridge.d.ts +38 -3
- package/dist/report-render/value-bridge.js +137 -6
- package/dist/report-render/views/chart-view.d.ts +42 -6
- package/dist/report-render/views/chart-view.js +70 -9
- package/dist/report-render/views/page-view.js +9 -10
- package/dist/runtime/assemble.js +2 -2
- package/dist/sandbox/client.d.ts +23 -32
- package/dist/sandbox/client.js +3 -11
- package/dist/sandbox/create-sandbox.d.ts +9 -24
- package/dist/sandbox/create-sandbox.js +15 -30
- package/dist/sandbox/docker-client.d.ts +12 -22
- package/dist/sandbox/docker-client.js +29 -43
- package/dist/sandbox/exec.d.ts +58 -0
- package/dist/sandbox/exec.js +197 -0
- package/dist/sandbox/identity.d.ts +5 -5
- package/dist/sandbox/identity.js +7 -10
- package/dist/sandbox/k8s-client.d.ts +4 -10
- package/dist/sandbox/k8s-client.js +5 -12
- package/dist/sandbox/liveness.d.ts +5 -12
- package/dist/sandbox/liveness.js +5 -12
- package/dist/sandbox/notification-sweep.d.ts +4 -7
- package/dist/sandbox/notification-sweep.js +4 -7
- package/dist/sandbox/reaper.d.ts +3 -3
- package/dist/sandbox/reaper.js +3 -3
- package/dist/sandbox/sandbox-error.d.ts +10 -11
- package/dist/sandbox/sandbox-error.js +10 -11
- package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
- package/dist/sandbox/sandbox-step-translate.js +1 -1
- package/dist/sandbox/types.d.ts +31 -99
- package/dist/sandbox/types.js +17 -84
- package/dist/state/active-sandboxes.d.ts +7 -32
- package/dist/state/active-sandboxes.js +11 -46
- package/dist/state/index.d.ts +1 -2
- package/dist/state/index.js +1 -1
- package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.d.ts +7 -0
- package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.js +12 -0
- package/dist/state/migrations/index.js +2 -0
- package/dist/state/schema.d.ts +1 -5
- package/dist/state/schema.js +1 -6
- package/dist/state/step-executions.js +1 -2
- package/dist/tasks/data-profile.js +7 -20
- package/dist/tasks/derive-table-exec.d.ts +4 -14
- package/dist/tasks/derive-table-exec.js +9 -24
- package/dist/tasks/extract-values.d.ts +2 -2
- package/dist/tasks/extract-values.js +4 -7
- package/dist/tools/bio/index.d.ts +2 -0
- package/dist/tools/bio/index.js +3 -0
- package/dist/tools/bio/keys.d.ts +11 -0
- package/dist/tools/bio/keys.js +15 -0
- package/dist/tools/bio/search-clinical-trials.d.ts +1 -1
- package/dist/tools/bio/search-patents.d.ts +46 -0
- package/dist/tools/bio/search-patents.js +134 -0
- package/dist/tools/bio/search-regulatory-approvals.d.ts +49 -0
- package/dist/tools/bio/search-regulatory-approvals.js +158 -0
- package/dist/tools/define-tool.d.ts +56 -13
- package/dist/tools/define-tool.js +28 -1
- package/dist/tools/execute-analysis.js +3 -3
- package/dist/tools/lib/amass-client.d.ts +586 -0
- package/dist/tools/lib/amass-client.js +492 -0
- package/dist/tools/lib/amass-config.d.ts +2 -0
- package/dist/tools/lib/amass-config.js +10 -0
- package/dist/tools/report-session/derive-table.d.ts +8 -9
- package/dist/tools/report-session/derive-table.js +3 -4
- package/dist/tools/report-session/preview-report.js +4 -49
- package/dist/tools/sandbox/list-available-packages.d.ts +1 -1
- package/dist/tools/sandbox/list-available-packages.js +5 -4
- package/dist/tools/workspace/edit-file.d.ts +5 -4
- package/dist/tools/workspace/edit-file.js +10 -13
- package/dist/tools/workspace/execute-command.d.ts +27 -42
- package/dist/tools/workspace/execute-command.js +42 -38
- package/dist/tools/workspace/index.d.ts +5 -6
- package/dist/tools/workspace/index.js +5 -6
- package/dist/tools/workspace/mutator.d.ts +43 -8
- package/dist/tools/workspace/mutator.js +45 -34
- package/dist/tools/workspace/run-exec.d.ts +3 -12
- package/dist/tools/workspace/run-exec.js +7 -24
- package/dist/tools/workspace/scan-inputs.d.ts +0 -3
- package/dist/tools/workspace/scan-inputs.js +0 -1
- package/dist/tools/workspace/write-file.d.ts +12 -3
- package/dist/tools/workspace/write-file.js +17 -13
- package/dist/workflows/sandbox-step.d.ts +7 -11
- package/dist/workflows/sandbox-step.js +24 -27
- package/package.json +3 -1
- package/dist/sandbox/await-exec.d.ts +0 -143
- package/dist/sandbox/await-exec.js +0 -417
- package/dist/sandbox/deliver-exec-event.d.ts +0 -25
- package/dist/sandbox/deliver-exec-event.js +0 -29
- package/dist/sandbox/digest.d.ts +0 -14
- package/dist/sandbox/digest.js +0 -17
- package/dist/sandbox/exec-id.d.ts +0 -12
- package/dist/sandbox/exec-id.js +0 -20
- package/dist/sandbox/hmac.d.ts +0 -62
- package/dist/sandbox/hmac.js +0 -72
- package/dist/sandbox/submit-exec.d.ts +0 -38
- package/dist/sandbox/submit-exec.js +0 -80
- package/dist/sandbox/watchdog.d.ts +0 -71
- package/dist/sandbox/watchdog.js +0 -161
|
@@ -400,7 +400,7 @@ export function queryPackages(rawSections, { names, query, language, limit }) {
|
|
|
400
400
|
* here, thus the census a model sees and the check a launch runs never
|
|
401
401
|
* disagree about what the source holds.
|
|
402
402
|
*/
|
|
403
|
-
export async function readInventorySections(deps) {
|
|
403
|
+
export async function readInventorySections(deps, analysisId) {
|
|
404
404
|
// The image record merges in when the host can read a valid one. An absent
|
|
405
405
|
// record and an invalid record both merge nothing, and neither is an
|
|
406
406
|
// error: the record is an enrichment, and the farm or pool inventory stays
|
|
@@ -422,8 +422,9 @@ export async function readInventorySections(deps) {
|
|
|
422
422
|
}
|
|
423
423
|
// Both farm container paths are tried when the host injects none, because
|
|
424
424
|
// the path keys on the declared toolchain and this read carries none.
|
|
425
|
+
const farmLockFile = typeof deps.farmLockFile === "function" ? deps.farmLockFile(analysisId) : deps.farmLockFile;
|
|
425
426
|
let lock = null;
|
|
426
|
-
for (const candidate of
|
|
427
|
+
for (const candidate of farmLockFile ? [farmLockFile] : DEFAULT_FARM_LOCK_FILES) {
|
|
427
428
|
lock = readFarmLockFile(candidate).unwrapOr(null);
|
|
428
429
|
if (lock !== null)
|
|
429
430
|
break;
|
|
@@ -502,8 +503,8 @@ export function createListAvailablePackagesTool(deps = {}) {
|
|
|
502
503
|
return `${language} packages`;
|
|
503
504
|
return "full package list";
|
|
504
505
|
},
|
|
505
|
-
execute: async (input) => {
|
|
506
|
-
const read = await readInventorySections(deps);
|
|
506
|
+
execute: async (input, ctx) => {
|
|
507
|
+
const read = await readInventorySections(deps, ctx.session.scope.analysisId);
|
|
507
508
|
// An unreadable inventory is an expected environment state — model it as an
|
|
508
509
|
// `available: false` data variant telling the caller the set is UNKNOWN,
|
|
509
510
|
// WITH the reason: without it, a structural fault (a damaged dependency
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* (compiled with the `gm` flags — multiline anchors), `new_string` may use
|
|
12
12
|
* capture-group references, and exactly one of `replace_all=true` or
|
|
13
13
|
* `expected_matches` gates the write. Provenance hashes the post-edit
|
|
14
|
-
* content —
|
|
14
|
+
* content — the mutator records it through the fold of this tool.
|
|
15
15
|
*/
|
|
16
|
+
import { type WithToolCallRecord } from "../define-tool.js";
|
|
16
17
|
import type { WorkspaceFilesystem } from "../../workspace/filesystem.js";
|
|
17
|
-
import type { WorkspaceMutator, WriteFileResult } from "./mutator.js";
|
|
18
|
+
import type { WorkspaceMutator, WriteFileResult, WriteRecord } from "./mutator.js";
|
|
18
19
|
/** Outcome of an `edit_file` call — expected outcomes are data variants, never throws. */
|
|
19
20
|
export type EditFileResult = {
|
|
20
21
|
readonly status: "file_not_found";
|
|
@@ -43,14 +44,14 @@ export type EditFileResult = {
|
|
|
43
44
|
readonly lines: readonly number[];
|
|
44
45
|
} | Exclude<WriteFileResult, {
|
|
45
46
|
status: "ok";
|
|
46
|
-
}> | {
|
|
47
|
+
}> | WithToolCallRecord<{
|
|
47
48
|
readonly status: "ok";
|
|
48
49
|
readonly path: string;
|
|
49
50
|
readonly replacements: number;
|
|
50
51
|
readonly bytesWritten: number;
|
|
51
52
|
/** Regex mode only: 1-based line numbers where the matches started. */
|
|
52
53
|
readonly lines?: readonly number[];
|
|
53
|
-
}
|
|
54
|
+
}, WriteRecord>;
|
|
54
55
|
export interface EditFileDeps {
|
|
55
56
|
readonly mutator: WorkspaceMutator;
|
|
56
57
|
/** Read seam used to fetch current file content for search/replace. */
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* (compiled with the `gm` flags — multiline anchors), `new_string` may use
|
|
12
12
|
* capture-group references, and exactly one of `replace_all=true` or
|
|
13
13
|
* `expected_matches` gates the write. Provenance hashes the post-edit
|
|
14
|
-
* content —
|
|
14
|
+
* content — the mutator records it through the fold of this tool.
|
|
15
15
|
*/
|
|
16
16
|
import { ok } from "neverthrow";
|
|
17
17
|
import { z } from "zod";
|
|
18
|
-
import { defineTool } from "../define-tool.js";
|
|
18
|
+
import { defineTool, withToolCallRecord } from "../define-tool.js";
|
|
19
19
|
import { unwrapOrThrow } from "../../lib/result.js";
|
|
20
20
|
const EditFileInputSchema = z.object({
|
|
21
21
|
path: z
|
|
@@ -108,9 +108,6 @@ function replaceRegex(content, pattern, replacement, expected) {
|
|
|
108
108
|
export function createEditFileTool(deps) {
|
|
109
109
|
return defineTool({
|
|
110
110
|
id: "edit_file",
|
|
111
|
-
// The mutator wraps the disk mutation in `ctx.runStep` itself, so the
|
|
112
|
-
// body runs unwrapped in the workflow body (see the harness-tools spec).
|
|
113
|
-
executionMode: "workflow",
|
|
114
111
|
description: "Edit a file in your working directory by replacing specific text. " +
|
|
115
112
|
"Read the file first to get the exact text. When replace_all is false " +
|
|
116
113
|
"(default), old_string must occur exactly once. For a bulk pattern " +
|
|
@@ -166,24 +163,24 @@ export function createEditFileTool(deps) {
|
|
|
166
163
|
lines: replaced.lines,
|
|
167
164
|
});
|
|
168
165
|
}
|
|
169
|
-
const
|
|
166
|
+
const write = await deps.mutator.writeFile({
|
|
170
167
|
path,
|
|
171
168
|
content: replaced.content,
|
|
172
169
|
toolName: "edit_file",
|
|
173
170
|
invocationId: ctx.invocationId,
|
|
174
|
-
runStep: ctx.runStep,
|
|
175
171
|
session: ctx.session,
|
|
176
172
|
});
|
|
177
|
-
if (
|
|
178
|
-
return ok(
|
|
173
|
+
if (write.status !== "ok")
|
|
174
|
+
return ok(write);
|
|
179
175
|
const lines = replaced.lines;
|
|
180
|
-
return ok({
|
|
176
|
+
return ok(withToolCallRecord({
|
|
181
177
|
status: "ok",
|
|
182
|
-
path:
|
|
178
|
+
path: write.path,
|
|
183
179
|
replacements: replaced.replacements,
|
|
184
|
-
bytesWritten:
|
|
180
|
+
bytesWritten: write.bytesWritten,
|
|
185
181
|
...(lines === undefined ? {} : { lines }),
|
|
186
|
-
});
|
|
182
|
+
}, write.record));
|
|
187
183
|
},
|
|
184
|
+
foldCallRecord: (record) => deps.mutator.recordWrite(record),
|
|
188
185
|
});
|
|
189
186
|
}
|
|
@@ -2,45 +2,46 @@
|
|
|
2
2
|
* `execute_command` — the single chokepoint through which sandbox commands
|
|
3
3
|
* run.
|
|
4
4
|
*
|
|
5
|
-
* Dependency-bearing factory (see the harness-durable-runtime spec): captures a
|
|
6
|
-
* live `SandboxRef` for the step
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Dependency-bearing factory (see the harness-durable-runtime spec): captures a
|
|
6
|
+
* `SandboxClient` and the live `SandboxRef` for the step. No other tool, agent,
|
|
7
|
+
* or workflow step is permitted to POST to sandbox-server's `/exec` directly —
|
|
8
|
+
* `SandboxClient` is intentionally injected only here so the durability /
|
|
9
|
+
* idempotency / liveness story `harness-sandbox-exec` owns holds uniformly
|
|
10
|
+
* across all sandbox command execution.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* The loop runs each call as one durable step, and the exec runs inside it,
|
|
13
|
+
* thus the exec id is the id of that step and a replay returns the cached
|
|
14
|
+
* result with no submit.
|
|
15
15
|
*
|
|
16
16
|
* Provenance for files written *inside* the sandbox by the executed command
|
|
17
17
|
* is NOT recorded here — sandbox-server emits provenance frames (see
|
|
18
18
|
* `sandbox-provenance-tracking`), and artifact registration reconciles them.
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
19
|
+
* The frame of each exec rides the call record, and the fold feeds it to the
|
|
20
|
+
* lineage collector of the step.
|
|
21
21
|
*/
|
|
22
|
+
import { type WithToolCallRecord } from "../define-tool.js";
|
|
22
23
|
import type { SandboxClient } from "../../sandbox/client.js";
|
|
23
|
-
import type { SandboxRef } from "../../sandbox/types.js";
|
|
24
|
+
import type { ProvenanceFrame, SandboxRef } from "../../sandbox/types.js";
|
|
24
25
|
import type { ProvenanceCollector } from "../../provenance/collector.js";
|
|
26
|
+
import { type BoundedExecResult } from "./result-bounds.js";
|
|
25
27
|
import type { Logger } from "../../lib/logger.js";
|
|
28
|
+
/** What one exec leaves for the lineage collector of the step. */
|
|
29
|
+
interface ExecCallRecord {
|
|
30
|
+
readonly command: readonly string[];
|
|
31
|
+
readonly exitCode: number | null;
|
|
32
|
+
readonly durationMs: number | null;
|
|
33
|
+
readonly provenance?: ProvenanceFrame;
|
|
34
|
+
}
|
|
35
|
+
type ExecuteCommandResult = {
|
|
36
|
+
readonly status: "ok";
|
|
37
|
+
} & BoundedExecResult;
|
|
26
38
|
export interface ExecuteCommandDeps {
|
|
27
39
|
/** Operational logging seam; omitted falls back to no-op. */
|
|
28
40
|
readonly logger?: Logger;
|
|
29
41
|
readonly sandboxClient: SandboxClient;
|
|
30
42
|
/** Live sandbox handle for the step. Created once per step at composition root. */
|
|
31
43
|
readonly sandbox: SandboxRef;
|
|
32
|
-
/**
|
|
33
|
-
readonly workflowId: string;
|
|
34
|
-
/** Stable across replay. The sandbox step's identifier within the workflow. */
|
|
35
|
-
readonly stepId: string;
|
|
36
|
-
/**
|
|
37
|
-
* Mints a stable per-call function id. The composition root closes over a
|
|
38
|
-
* monotonic counter; the agent loop's tool-call order is replay-deterministic
|
|
39
|
-
* (the LLM call wrapping it is a cached DBOS step), so the counter reaches
|
|
40
|
-
* the same value at each call site on replay.
|
|
41
|
-
*/
|
|
42
|
-
readonly nextFunctionId: () => string;
|
|
43
|
-
/** Absolute unix-ms deadline for `awaitExec`. Typically derived from `step.timeout`. */
|
|
44
|
+
/** Absolute unix-ms deadline of the exec. Typically derived from `step.timeout`. */
|
|
44
45
|
readonly deadlineMs: () => number;
|
|
45
46
|
/**
|
|
46
47
|
* In-sandbox absolute path of the agent's working directory (e.g.
|
|
@@ -49,8 +50,6 @@ export interface ExecuteCommandDeps {
|
|
|
49
50
|
* and as the base a supplied relative `cwd` resolves against (see the harness-workspace-tools spec).
|
|
50
51
|
*/
|
|
51
52
|
readonly defaultCwd: string;
|
|
52
|
-
/** Tag the active-sandbox row with the in-flight execId for the liveness watchdog. */
|
|
53
|
-
readonly markExecActive?: (execId: string) => Promise<void>;
|
|
54
53
|
/**
|
|
55
54
|
* Step-scoped lineage collector. Each exec's `ExecResult.provenance`
|
|
56
55
|
* frame is fed here (reads → inputs, writes → outputs) so post-step
|
|
@@ -65,19 +64,5 @@ export declare function createExecuteCommandTool(deps: ExecuteCommandDeps): impo
|
|
|
65
64
|
cwd?: string | undefined;
|
|
66
65
|
env?: Record<string, string> | undefined;
|
|
67
66
|
timeoutSeconds?: number | undefined;
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
exitCode: number | null;
|
|
71
|
-
stdout: string;
|
|
72
|
-
stderr: string;
|
|
73
|
-
stdoutTruncated: boolean;
|
|
74
|
-
stderrTruncated: boolean;
|
|
75
|
-
stdoutTotalLength: number;
|
|
76
|
-
stderrTotalLength: number;
|
|
77
|
-
durationMs: number | null;
|
|
78
|
-
timedOut: boolean;
|
|
79
|
-
syntheticFailure?: {
|
|
80
|
-
readonly reason: string;
|
|
81
|
-
};
|
|
82
|
-
status: "ok";
|
|
83
|
-
}>;
|
|
67
|
+
}, ExecuteCommandResult | WithToolCallRecord<ExecuteCommandResult, ExecCallRecord>>;
|
|
68
|
+
export {};
|
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
* `execute_command` — the single chokepoint through which sandbox commands
|
|
3
3
|
* run.
|
|
4
4
|
*
|
|
5
|
-
* Dependency-bearing factory (see the harness-durable-runtime spec): captures a
|
|
6
|
-
* live `SandboxRef` for the step
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Dependency-bearing factory (see the harness-durable-runtime spec): captures a
|
|
6
|
+
* `SandboxClient` and the live `SandboxRef` for the step. No other tool, agent,
|
|
7
|
+
* or workflow step is permitted to POST to sandbox-server's `/exec` directly —
|
|
8
|
+
* `SandboxClient` is intentionally injected only here so the durability /
|
|
9
|
+
* idempotency / liveness story `harness-sandbox-exec` owns holds uniformly
|
|
10
|
+
* across all sandbox command execution.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* The loop runs each call as one durable step, and the exec runs inside it,
|
|
13
|
+
* thus the exec id is the id of that step and a replay returns the cached
|
|
14
|
+
* result with no submit.
|
|
15
15
|
*
|
|
16
16
|
* Provenance for files written *inside* the sandbox by the executed command
|
|
17
17
|
* is NOT recorded here — sandbox-server emits provenance frames (see
|
|
18
18
|
* `sandbox-provenance-tracking`), and artifact registration reconciles them.
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
19
|
+
* The frame of each exec rides the call record, and the fold feeds it to the
|
|
20
|
+
* lineage collector of the step.
|
|
21
21
|
*/
|
|
22
22
|
import { posix as posixPath } from "node:path";
|
|
23
23
|
import { ok } from "neverthrow";
|
|
24
24
|
import { z } from "zod";
|
|
25
|
-
import { defineTool } from "../define-tool.js";
|
|
25
|
+
import { defineTool, withToolCallRecord } from "../define-tool.js";
|
|
26
26
|
import { feedExecFrame } from "../../provenance/exec-frame.js";
|
|
27
27
|
import { EXEC_STREAM_BYTE_CAP, boundExecResult } from "./result-bounds.js";
|
|
28
28
|
import { runSandboxExec } from "./run-exec.js";
|
|
@@ -50,12 +50,9 @@ function scriptToken(command) {
|
|
|
50
50
|
return command.find((arg) => SCRIPT_EXTENSIONS.test(arg));
|
|
51
51
|
}
|
|
52
52
|
export function createExecuteCommandTool(deps) {
|
|
53
|
-
const { sandboxClient, sandbox,
|
|
53
|
+
const { sandboxClient, sandbox, deadlineMs, defaultCwd, lineageCollector, mountRoot } = deps;
|
|
54
54
|
return defineTool({
|
|
55
55
|
id: "execute_command",
|
|
56
|
-
// `awaitExec`-recv is body-only (`DBOS.recv`), so this runs unwrapped in
|
|
57
|
-
// the workflow body; durability is self-owned (submit step + body recv). See the harness-tools spec.
|
|
58
|
-
executionMode: "workflow",
|
|
59
56
|
description: "Run a command in the sandbox and return its stdout/stderr/exit code. " +
|
|
60
57
|
"Use for scripts, CLI tools, shell pipes, and anything the workspace " +
|
|
61
58
|
`tools don't express. stdout and stderr are each capped at ${EXEC_STREAM_BYTE_CAP / (1024 * 1024)} MiB; the end ` +
|
|
@@ -88,40 +85,47 @@ export function createExecuteCommandTool(deps) {
|
|
|
88
85
|
// outlives the turn that ran it.
|
|
89
86
|
describeCall: ({ command }) => scriptToken(command) ?? command.join(" "),
|
|
90
87
|
execute: async ({ command, cwd, env, timeoutSeconds }, ctx) => {
|
|
91
|
-
const execId = `${workflowId}:${stepId}:${nextFunctionId()}`;
|
|
92
88
|
const effectiveCwd = cwd === undefined ? defaultCwd : cwd.startsWith("/") ? cwd : posixPath.join(defaultCwd, cwd);
|
|
93
89
|
const result = await runSandboxExec({
|
|
94
90
|
sandboxClient,
|
|
95
91
|
sandbox,
|
|
96
|
-
execId,
|
|
97
92
|
command,
|
|
98
93
|
cwd: effectiveCwd,
|
|
99
94
|
...(env === undefined ? {} : { env }),
|
|
100
95
|
...(timeoutSeconds === undefined ? {} : { timeoutSeconds }),
|
|
101
96
|
deadlineMs: deadlineMs(),
|
|
102
97
|
emit: ctx.emit,
|
|
103
|
-
...(markExecActive ? { markExecActive } : {}),
|
|
104
98
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
99
|
+
const bounded = { status: "ok", ...boundExecResult(result) };
|
|
100
|
+
if (!lineageCollector || !mountRoot)
|
|
101
|
+
return ok(bounded);
|
|
102
|
+
const record = {
|
|
103
|
+
command,
|
|
104
|
+
exitCode: result.exitCode,
|
|
105
|
+
durationMs: result.durationMs,
|
|
106
|
+
...(result.provenance ? { provenance: result.provenance } : {}),
|
|
107
|
+
};
|
|
108
|
+
return ok(withToolCallRecord(bounded, record));
|
|
109
|
+
},
|
|
110
|
+
// Best-effort: a collector failure must never fail the exec.
|
|
111
|
+
foldCallRecord: (record) => {
|
|
112
|
+
if (!lineageCollector || !mountRoot)
|
|
113
|
+
return;
|
|
114
|
+
try {
|
|
115
|
+
feedExecFrame({
|
|
116
|
+
collector: lineageCollector,
|
|
117
|
+
mountRoot,
|
|
118
|
+
command: record.command,
|
|
119
|
+
exitCode: record.exitCode,
|
|
120
|
+
durationMs: record.durationMs,
|
|
121
|
+
...(deps.logger ? { logger: deps.logger } : {}),
|
|
122
|
+
...(record.provenance ? { provenance: record.provenance } : {}),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const logger = (deps.logger ?? createNoopLogger()).named("execute_command");
|
|
127
|
+
logger.warn("provenance frame handling failed (non-fatal)", logger.errorFields(err));
|
|
123
128
|
}
|
|
124
|
-
return ok({ status: "ok", ...boundExecResult(result) });
|
|
125
129
|
},
|
|
126
130
|
});
|
|
127
131
|
}
|
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
* Read surface (sandbox-independent): semantic file search, raw read + grep
|
|
5
5
|
* over the workspace filesystem seam, plus file/plan display.
|
|
6
6
|
*
|
|
7
|
-
* Mutate surface
|
|
8
|
-
* sandbox
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* submit/await path through `runSandboxExec`.
|
|
7
|
+
* Mutate surface: `execute_command` (single chokepoint for sandbox commands,
|
|
8
|
+
* sandbox-gated), `write_file` and `edit_file` scoped to the writable
|
|
9
|
+
* directory of the agent. `execute_command` drives sandbox-server's `/exec`
|
|
10
|
+
* through `runSandboxExec`; `write_file` / `edit_file` write host-side through
|
|
11
|
+
* the workspace mutator.
|
|
13
12
|
*/
|
|
14
13
|
export * from "./workspace-search.js";
|
|
15
14
|
export * from "./show-file.js";
|
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
* Read surface (sandbox-independent): semantic file search, raw read + grep
|
|
5
5
|
* over the workspace filesystem seam, plus file/plan display.
|
|
6
6
|
*
|
|
7
|
-
* Mutate surface
|
|
8
|
-
* sandbox
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* submit/await path through `runSandboxExec`.
|
|
7
|
+
* Mutate surface: `execute_command` (single chokepoint for sandbox commands,
|
|
8
|
+
* sandbox-gated), `write_file` and `edit_file` scoped to the writable
|
|
9
|
+
* directory of the agent. `execute_command` drives sandbox-server's `/exec`
|
|
10
|
+
* through `runSandboxExec`; `write_file` / `edit_file` write host-side through
|
|
11
|
+
* the workspace mutator.
|
|
13
12
|
*/
|
|
14
13
|
// Read surface
|
|
15
14
|
export * from "./workspace-search.js";
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
* invariant is concentrated in one place instead of being a per-tool
|
|
10
10
|
* convention.
|
|
11
11
|
*
|
|
12
|
+
* The write and its provenance record are two calls. `writeFile` lands the
|
|
13
|
+
* bytes and gives back the record of the write; the tool carries the record as
|
|
14
|
+
* its call record, and its fold hands it to `recordWrite`. The loop caches the
|
|
15
|
+
* tool call as one step, thus a replay never lands the bytes again, and the
|
|
16
|
+
* fold still records the write into fresh process state.
|
|
17
|
+
*
|
|
12
18
|
* Two realizations serve the two agent contexts. `createWorkspaceMutator`
|
|
13
19
|
* closes over fixed per-step coordinates and records into the step-scoped
|
|
14
20
|
* lineage collector (the sandbox agents). `createSessionWorkspaceMutator`
|
|
@@ -25,7 +31,6 @@
|
|
|
25
31
|
*/
|
|
26
32
|
import type { AgentSession } from "../../auth/types.js";
|
|
27
33
|
import type { Logger } from "../../lib/logger.js";
|
|
28
|
-
import type { RunStep } from "../../loop/types.js";
|
|
29
34
|
import type { ProvenanceCollector } from "../../provenance/collector.js";
|
|
30
35
|
import { type ProvenanceSeam } from "../../provenance/seam.js";
|
|
31
36
|
import { type ResolveWorkspaceRoot } from "../../workspace/paths.js";
|
|
@@ -44,6 +49,31 @@ export type WriteFileResult = {
|
|
|
44
49
|
readonly status: "symlink_denied";
|
|
45
50
|
readonly path: string;
|
|
46
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* What one landed write leaves for provenance: the hash and the size of the
|
|
54
|
+
* exact bytes on disk, computed at the landing. Plain JSON, because the step
|
|
55
|
+
* cache of the tool call holds it.
|
|
56
|
+
*/
|
|
57
|
+
export interface WriteRecord {
|
|
58
|
+
readonly analysisId: string;
|
|
59
|
+
/** The thread of a session write; absent under a run. */
|
|
60
|
+
readonly threadId?: string;
|
|
61
|
+
/** Analysis-root-relative, forward-slashed. */
|
|
62
|
+
readonly path: string;
|
|
63
|
+
readonly hash: string;
|
|
64
|
+
readonly size: number;
|
|
65
|
+
readonly toolName: MutateToolName;
|
|
66
|
+
readonly invocationId: string;
|
|
67
|
+
}
|
|
68
|
+
/** `writeFile` gives back the result, and on success the record of the write for `recordWrite`. */
|
|
69
|
+
export type WriteOutcome = {
|
|
70
|
+
readonly status: "ok";
|
|
71
|
+
readonly path: string;
|
|
72
|
+
readonly bytesWritten: number;
|
|
73
|
+
readonly record: WriteRecord;
|
|
74
|
+
} | Exclude<WriteFileResult, {
|
|
75
|
+
status: "ok";
|
|
76
|
+
}>;
|
|
47
77
|
/**
|
|
48
78
|
* Agent-visible name of the tool driving a confined write. Rides the write args
|
|
49
79
|
* so a successful write is attributed to the invoking tool in provenance
|
|
@@ -73,20 +103,25 @@ export interface WorkspaceMutator {
|
|
|
73
103
|
* the invoking tool so a successful write is attributed to it in
|
|
74
104
|
* provenance. `invocationId` is the tool call's loop id — pass the tool
|
|
75
105
|
* context's `invocationId`: it rides the provenance record so the write's
|
|
76
|
-
* call activity gets a deterministic identity. `
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
106
|
+
* call activity gets a deterministic identity. `session` is the calling
|
|
107
|
+
* agent's session — pass the tool context's `session`: the step-scoped
|
|
108
|
+
* realization ignores it, the session-scoped one resolves its coordinates
|
|
109
|
+
* and its provenance attribution from it.
|
|
110
|
+
*
|
|
111
|
+
* Records nothing: a successful write gives back its record for `recordWrite`.
|
|
81
112
|
*/
|
|
82
113
|
writeFile(args: {
|
|
83
114
|
readonly path: string;
|
|
84
115
|
readonly content: string;
|
|
85
116
|
readonly toolName: MutateToolName;
|
|
86
117
|
readonly invocationId: string;
|
|
87
|
-
readonly runStep: RunStep;
|
|
88
118
|
readonly session: AgentSession;
|
|
89
|
-
}): Promise<
|
|
119
|
+
}): Promise<WriteOutcome>;
|
|
120
|
+
/**
|
|
121
|
+
* Record one landed write in provenance. A tool calls it from its call-record
|
|
122
|
+
* fold, thus the record reaches process-local state on each replay too.
|
|
123
|
+
*/
|
|
124
|
+
recordWrite(record: WriteRecord): void;
|
|
90
125
|
}
|
|
91
126
|
export declare function createWorkspaceMutator(deps: WorkspaceMutatorDeps): WorkspaceMutator;
|
|
92
127
|
/** Construction deps of the session-scoped realization — see {@link createSessionWorkspaceMutator}. */
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
* invariant is concentrated in one place instead of being a per-tool
|
|
10
10
|
* convention.
|
|
11
11
|
*
|
|
12
|
+
* The write and its provenance record are two calls. `writeFile` lands the
|
|
13
|
+
* bytes and gives back the record of the write; the tool carries the record as
|
|
14
|
+
* its call record, and its fold hands it to `recordWrite`. The loop caches the
|
|
15
|
+
* tool call as one step, thus a replay never lands the bytes again, and the
|
|
16
|
+
* fold still records the write into fresh process state.
|
|
17
|
+
*
|
|
12
18
|
* Two realizations serve the two agent contexts. `createWorkspaceMutator`
|
|
13
19
|
* closes over fixed per-step coordinates and records into the step-scoped
|
|
14
20
|
* lineage collector (the sandbox agents). `createSessionWorkspaceMutator`
|
|
@@ -107,9 +113,9 @@ async function landBytes(prefix, absolute, bytes) {
|
|
|
107
113
|
}
|
|
108
114
|
/**
|
|
109
115
|
* The shared write gauntlet both realizations run: resolve + confine
|
|
110
|
-
* (`resolveForWrite`), then the hardened landing
|
|
111
|
-
*
|
|
112
|
-
*
|
|
116
|
+
* (`resolveForWrite`), then the hardened landing. A refusal comes back as data;
|
|
117
|
+
* an ok carries what the caller's provenance record needs — the
|
|
118
|
+
* analysis-relative path and the exact bytes that landed.
|
|
113
119
|
*/
|
|
114
120
|
async function confinedWrite(args) {
|
|
115
121
|
const scoped = resolveForWrite({
|
|
@@ -129,51 +135,46 @@ async function confinedWrite(args) {
|
|
|
129
135
|
const agentPath = `/${args.analysisId}/${relative}`;
|
|
130
136
|
const bytes = Buffer.from(args.content, "utf8");
|
|
131
137
|
const prefix = resolvePath(args.workingDir);
|
|
132
|
-
|
|
133
|
-
// `dispatchTools` in loop/run-agent.ts), so a DBOS replay re-runs
|
|
134
|
-
// this body. The step wrapper caches the landing: a replay returns
|
|
135
|
-
// the recorded outcome instead of touching the disk again. On the
|
|
136
|
-
// chat route the injected `runStep` is the passthrough — the same
|
|
137
|
-
// call, no durability, no fork of this path.
|
|
138
|
-
const landed = await args.runStep("write", () => landBytes(prefix, scoped.absolute, bytes));
|
|
138
|
+
const landed = await landBytes(prefix, scoped.absolute, bytes);
|
|
139
139
|
if (landed !== "ok")
|
|
140
140
|
return { status: landed };
|
|
141
141
|
return { status: "ok", relative, agentPath, bytes };
|
|
142
142
|
}
|
|
143
143
|
export function createWorkspaceMutator(deps) {
|
|
144
144
|
return {
|
|
145
|
-
async writeFile({ path, content, toolName, invocationId
|
|
145
|
+
async writeFile({ path, content, toolName, invocationId }) {
|
|
146
146
|
const landed = await confinedWrite({
|
|
147
147
|
workspaceRoot: deps.workspaceRoot,
|
|
148
148
|
analysisId: deps.analysisId,
|
|
149
149
|
workingDir: deps.workingDir,
|
|
150
150
|
path,
|
|
151
151
|
content,
|
|
152
|
-
runStep,
|
|
153
152
|
});
|
|
154
153
|
if (landed.status !== "ok")
|
|
155
154
|
return { status: landed.status, path };
|
|
156
|
-
// Attest the write in-process from the exact bytes just written — the
|
|
157
|
-
// seam owns write provenance the same way it owns confinement. The
|
|
158
|
-
// record lands outside the write step on purpose: the collector is
|
|
159
|
-
// process-local state, so a recovered replay must re-record into the
|
|
160
|
-
// fresh collector even while the cached step skips the disk write.
|
|
161
|
-
//
|
|
162
155
|
// `invocationId` is replay-stable: the model turn that minted the tool
|
|
163
156
|
// call is a durably cached step, so a re-execution replays the same id.
|
|
164
157
|
// That is what lets the bridge key a DETERMINISTIC call-activity
|
|
165
158
|
// identifier on it — a wall-clock stamp here would be re-minted per
|
|
166
159
|
// replay and must never reach an identifier or a formal PROV position.
|
|
167
|
-
|
|
168
|
-
deps.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
160
|
+
const record = {
|
|
161
|
+
analysisId: deps.analysisId,
|
|
162
|
+
path: landed.relative,
|
|
163
|
+
hash: computeSha256(landed.bytes),
|
|
164
|
+
size: landed.bytes.length,
|
|
165
|
+
toolName,
|
|
166
|
+
invocationId,
|
|
167
|
+
};
|
|
168
|
+
return { status: "ok", path: landed.agentPath, bytesWritten: landed.bytes.length, record };
|
|
169
|
+
},
|
|
170
|
+
recordWrite(record) {
|
|
171
|
+
deps.lineageCollector?.recordFileToolWrite({
|
|
172
|
+
path: record.path,
|
|
173
|
+
hash: record.hash,
|
|
174
|
+
size: record.size,
|
|
175
|
+
toolName: record.toolName,
|
|
176
|
+
invocationId: record.invocationId,
|
|
177
|
+
});
|
|
177
178
|
},
|
|
178
179
|
};
|
|
179
180
|
}
|
|
@@ -194,7 +195,7 @@ export function createSessionWorkspaceMutator(deps) {
|
|
|
194
195
|
const logger = (deps.logger ?? createNoopLogger()).named("workspace-mutator");
|
|
195
196
|
const observe = bindSessionEmit(deps.provenance, logger);
|
|
196
197
|
return {
|
|
197
|
-
async writeFile({ path, content, toolName, invocationId,
|
|
198
|
+
async writeFile({ path, content, toolName, invocationId, session }) {
|
|
198
199
|
// Only an analysis scope has a workspace tree; under any other
|
|
199
200
|
// scope there is nothing in scope to write.
|
|
200
201
|
const scope = session.scope;
|
|
@@ -209,21 +210,31 @@ export function createSessionWorkspaceMutator(deps) {
|
|
|
209
210
|
workingDir: workspaceRoot,
|
|
210
211
|
path,
|
|
211
212
|
content,
|
|
212
|
-
runStep,
|
|
213
213
|
});
|
|
214
214
|
if (landed.status !== "ok")
|
|
215
215
|
return { status: landed.status, path };
|
|
216
|
-
|
|
217
|
-
type: "write-file",
|
|
216
|
+
const record = {
|
|
218
217
|
analysisId: scope.analysisId,
|
|
219
218
|
...(scope.threadId !== undefined ? { threadId: scope.threadId } : {}),
|
|
220
219
|
path: landed.relative,
|
|
221
220
|
hash: computeSha256(landed.bytes),
|
|
222
221
|
size: landed.bytes.length,
|
|
223
|
-
|
|
222
|
+
toolName,
|
|
224
223
|
invocationId,
|
|
224
|
+
};
|
|
225
|
+
return { status: "ok", path: landed.agentPath, bytesWritten: landed.bytes.length, record };
|
|
226
|
+
},
|
|
227
|
+
recordWrite(record) {
|
|
228
|
+
observe({
|
|
229
|
+
type: "write-file",
|
|
230
|
+
analysisId: record.analysisId,
|
|
231
|
+
...(record.threadId !== undefined ? { threadId: record.threadId } : {}),
|
|
232
|
+
path: record.path,
|
|
233
|
+
hash: record.hash,
|
|
234
|
+
size: record.size,
|
|
235
|
+
tool: record.toolName,
|
|
236
|
+
invocationId: record.invocationId,
|
|
225
237
|
});
|
|
226
|
-
return { status: "ok", path: landed.agentPath, bytesWritten: landed.bytes.length };
|
|
227
238
|
},
|
|
228
239
|
};
|
|
229
240
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal helper used by dependency-bearing tools to drive one sandbox exec
|
|
3
|
-
* through the `SandboxClient`.
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
* `list_available_refs` use this same replay-safe submit/await path rather
|
|
7
|
-
* than a parallel protocol.
|
|
3
|
+
* through the `SandboxClient`. It wraps each sandbox event in a
|
|
4
|
+
* `data-sandbox-event` part, thus `execute_command` and the container readout
|
|
5
|
+
* of `scan_inputs` report progress in one shape.
|
|
8
6
|
*
|
|
9
7
|
* Not a registered tool — `defineTool` is called by the user-facing tools
|
|
10
8
|
* (`execute-command.ts`) which wrap this.
|
|
@@ -15,18 +13,11 @@ import type { EmitFn } from "../define-tool.js";
|
|
|
15
13
|
export interface RunExecArgs {
|
|
16
14
|
readonly sandboxClient: SandboxClient;
|
|
17
15
|
readonly sandbox: SandboxRef;
|
|
18
|
-
readonly execId: string;
|
|
19
16
|
readonly command: readonly string[];
|
|
20
17
|
readonly cwd?: string;
|
|
21
18
|
readonly env?: Record<string, string>;
|
|
22
19
|
readonly timeoutSeconds?: number;
|
|
23
20
|
readonly deadlineMs: number;
|
|
24
21
|
readonly emit: EmitFn;
|
|
25
|
-
/**
|
|
26
|
-
* Tag the active-sandbox registry row with this execId before awaiting, so
|
|
27
|
-
* the liveness watchdog can target the in-flight exec when the sandbox dies
|
|
28
|
-
* mid-command. Best-effort: a registry write failure must not fail the exec.
|
|
29
|
-
*/
|
|
30
|
-
readonly markExecActive?: (execId: string) => Promise<void>;
|
|
31
22
|
}
|
|
32
23
|
export declare function runSandboxExec(args: RunExecArgs): Promise<ExecResult>;
|