@inflexa-ai/harness 0.42.2 → 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/sandbox/shared.d.ts +1 -6
- package/dist/agents/sandbox/shared.js +0 -15
- 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/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/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/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
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A thin adapter over the `WorkspaceMutator` seam (see the harness-durable-runtime / harness-workspace-tools specs): the
|
|
6
6
|
* mutator owns resolve + confine + hardened host write + provenance. This tool
|
|
7
|
-
*
|
|
7
|
+
* declares the input schema, forwards the write, and carries the record of the
|
|
8
|
+
* write to the fold. `edit_file` rides the same seam.
|
|
8
9
|
*/
|
|
9
10
|
import { ok } from "neverthrow";
|
|
10
11
|
import { z } from "zod";
|
|
11
|
-
import { defineTool } from "../define-tool.js";
|
|
12
|
+
import { defineTool, withToolCallRecord } from "../define-tool.js";
|
|
12
13
|
const WriteFileInputSchema = z.object({
|
|
13
14
|
path: z
|
|
14
15
|
.string()
|
|
@@ -21,9 +22,6 @@ const WriteFileInputSchema = z.object({
|
|
|
21
22
|
export function createWriteFileTool(deps) {
|
|
22
23
|
return defineTool({
|
|
23
24
|
id: "write_file",
|
|
24
|
-
// The mutator wraps the disk mutation in `ctx.runStep` itself, so the
|
|
25
|
-
// body runs unwrapped in the workflow body (see the harness-tools spec).
|
|
26
|
-
executionMode: "workflow",
|
|
27
25
|
description: "Write a UTF-8 text file in your working directory. Relative paths " +
|
|
28
26
|
"resolve against it. The write replaces an existing file whole, and it makes " +
|
|
29
27
|
"missing parent directories. On success it returns `status: ok`, the absolute " +
|
|
@@ -34,13 +32,19 @@ export function createWriteFileTool(deps) {
|
|
|
34
32
|
// The path only. `content` is a whole file and must never ride a display
|
|
35
33
|
// channel, which the emit-site length cap enforces regardless.
|
|
36
34
|
describeCall: ({ path }) => path,
|
|
37
|
-
execute: async ({ path, content }, ctx) =>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
execute: async ({ path, content }, ctx) => {
|
|
36
|
+
const write = await deps.mutator.writeFile({
|
|
37
|
+
path,
|
|
38
|
+
content,
|
|
39
|
+
toolName: "write_file",
|
|
40
|
+
invocationId: ctx.invocationId,
|
|
41
|
+
session: ctx.session,
|
|
42
|
+
});
|
|
43
|
+
if (write.status !== "ok")
|
|
44
|
+
return ok(write);
|
|
45
|
+
const { record, ...result } = write;
|
|
46
|
+
return ok(withToolCallRecord(result, record));
|
|
47
|
+
},
|
|
48
|
+
foldCallRecord: (record) => deps.mutator.recordWrite(record),
|
|
45
49
|
});
|
|
46
50
|
}
|
|
@@ -91,8 +91,7 @@ export interface SandboxStepInput {
|
|
|
91
91
|
readonly resources: ResourceSpec;
|
|
92
92
|
/**
|
|
93
93
|
* Per-step execution budget in seconds. The body translates this into the
|
|
94
|
-
* absolute unix-ms deadline that `
|
|
95
|
-
* backstop. Comes from the plan's `step.timeout` (defaulted on the parent
|
|
94
|
+
* absolute unix-ms deadline that each exec of the step honours. Comes from the plan's `step.timeout` (defaulted on the parent
|
|
96
95
|
* side); falls back to `DEFAULT_STEP_TIMEOUT_SECONDS` when unset so a
|
|
97
96
|
* client that omits the field still gets a non-pathological ceiling.
|
|
98
97
|
*/
|
|
@@ -184,17 +183,13 @@ export interface PostStepArtifacts {
|
|
|
184
183
|
/**
|
|
185
184
|
* Per-step coordinates the workflow body computes once and threads to the
|
|
186
185
|
* deps factory. The parent supplies the durable inputs; the factory
|
|
187
|
-
* supplies the live sandbox ref
|
|
188
|
-
* deadline.
|
|
186
|
+
* supplies the live sandbox ref and the deadline.
|
|
189
187
|
*/
|
|
190
188
|
export interface SandboxAgentBuildContext {
|
|
191
189
|
readonly input: SandboxStepInput;
|
|
192
190
|
readonly session: RunSession;
|
|
193
191
|
readonly sandbox: SandboxRef;
|
|
194
|
-
/** Workflow-id used to scope sandbox callbacks + workspace mutate provenance. */
|
|
195
|
-
readonly workflowId: string;
|
|
196
192
|
readonly stepWritePrefix: string;
|
|
197
|
-
readonly nextFunctionId: () => string;
|
|
198
193
|
readonly deadlineMs: () => number;
|
|
199
194
|
/**
|
|
200
195
|
* Step-scoped lineage collector. The body owns one per step and threads
|
|
@@ -302,10 +297,11 @@ export interface PostStepContext {
|
|
|
302
297
|
export declare function readStepFileMetadata(checkpoint: StepFileMetadata | readonly FileMetadataEntry[]): StepFileMetadata;
|
|
303
298
|
/**
|
|
304
299
|
* Build the step's lineage collector from its durable input. The agent loop
|
|
305
|
-
* feeds each exec's provenance frame
|
|
306
|
-
* resulting input/script edges.
|
|
307
|
-
*
|
|
308
|
-
*
|
|
300
|
+
* feeds each exec's provenance frame and each file-tool write into it;
|
|
301
|
+
* post-step registration reads the resulting input/script edges.
|
|
302
|
+
* Reconstructed deterministically on replay — the loop folds the call record
|
|
303
|
+
* of each cached tool call into it again, in call order (see the
|
|
304
|
+
* harness-durable-runtime spec).
|
|
309
305
|
*
|
|
310
306
|
* Split out of the body, and taking only the fields it reads, so the seeding is
|
|
311
307
|
* exercisable without a live workflow: `dependsOn` is what makes a same-run edge
|
|
@@ -69,10 +69,6 @@ export const CAPPED_OUT_EMPTY_REASON = "The step hit its iteration cap with no o
|
|
|
69
69
|
*/
|
|
70
70
|
export const CHILD_SUSPENDED_TOPIC = "child-suspended";
|
|
71
71
|
// ── Helpers ───────────────────────────────────────────────────────────
|
|
72
|
-
function nextFunctionIdFactory() {
|
|
73
|
-
let n = 0;
|
|
74
|
-
return () => `fn-${(n++).toString(36)}`;
|
|
75
|
-
}
|
|
76
72
|
const NO_STEP_FILE_METADATA = { entries: [], messages: [] };
|
|
77
73
|
/** Normalizes a pre-`messages` checkpoint (a bare entries array) for replay. */
|
|
78
74
|
export function readStepFileMetadata(checkpoint) {
|
|
@@ -95,10 +91,11 @@ function userFacingStepFailure(errorClass) {
|
|
|
95
91
|
}
|
|
96
92
|
/**
|
|
97
93
|
* Build the step's lineage collector from its durable input. The agent loop
|
|
98
|
-
* feeds each exec's provenance frame
|
|
99
|
-
* resulting input/script edges.
|
|
100
|
-
*
|
|
101
|
-
*
|
|
94
|
+
* feeds each exec's provenance frame and each file-tool write into it;
|
|
95
|
+
* post-step registration reads the resulting input/script edges.
|
|
96
|
+
* Reconstructed deterministically on replay — the loop folds the call record
|
|
97
|
+
* of each cached tool call into it again, in call order (see the
|
|
98
|
+
* harness-durable-runtime spec).
|
|
102
99
|
*
|
|
103
100
|
* Split out of the body, and taking only the fields it reads, so the seeding is
|
|
104
101
|
* exercisable without a live workflow: `dependsOn` is what makes a same-run edge
|
|
@@ -181,15 +178,15 @@ export async function runSandboxStepBody(input, deps) {
|
|
|
181
178
|
const session = forSubAgent(input.runSession, input.agentId);
|
|
182
179
|
const writePrefix = deps.resolveWritePrefix(input);
|
|
183
180
|
const lineageCollector = createLineageCollector(input);
|
|
184
|
-
// (2a) sandbox.mint — checkpoint the machine's identity (name
|
|
181
|
+
// (2a) sandbox.mint — checkpoint the machine's identity (its name)
|
|
185
182
|
// BEFORE it is spawned (see the harness-sandbox-exec spec). Durable-before-create is what makes (2b)
|
|
186
183
|
// idempotent: a crash between spawn and the spawn checkpoint re-runs (2b)
|
|
187
184
|
// with the same identity, which adopts the already-created machine instead
|
|
188
185
|
// of leaking a second one.
|
|
189
186
|
const identity = await DBOS.runStep(() => Promise.resolve(mintSandboxIdentity(input.runId)), { name: "sandbox.mint" });
|
|
190
187
|
// (2b) sandbox.create — spawn (or adopt) the machine under the minted
|
|
191
|
-
// identity. The handle
|
|
192
|
-
//
|
|
188
|
+
// identity. The handle is cached so recovery picks the same machine back up
|
|
189
|
+
// without re-provisioning.
|
|
193
190
|
const sandboxSpec = {
|
|
194
191
|
childWorkflowId,
|
|
195
192
|
image: input.image,
|
|
@@ -215,9 +212,8 @@ export async function runSandboxStepBody(input, deps) {
|
|
|
215
212
|
}, { name: "sandbox.recheck-alive" });
|
|
216
213
|
// (3) runAgent — the harness loop with durableStep.
|
|
217
214
|
// The step deadline is captured ONCE at step start from the checkpointed
|
|
218
|
-
// clock so it reproduces on replay —
|
|
219
|
-
//
|
|
220
|
-
// `DBOS.recv` sequence on recovery (see the harness-durable-runtime spec). `deadlineMs` is a getter so
|
|
215
|
+
// clock so it reproduces on replay — a raw `Date.now()` here would grow the
|
|
216
|
+
// deadline on each recovery (see the harness-durable-runtime spec). `deadlineMs` is a getter so
|
|
221
217
|
// deps read the absolute ms without holding a captured value; returning a
|
|
222
218
|
// fresh `now + timeout` per call would make a step with N tool calls runnable
|
|
223
219
|
// for up to N × `timeoutSeconds`.
|
|
@@ -228,9 +224,7 @@ export async function runSandboxStepBody(input, deps) {
|
|
|
228
224
|
input,
|
|
229
225
|
session,
|
|
230
226
|
sandbox,
|
|
231
|
-
workflowId: childWorkflowId,
|
|
232
227
|
stepWritePrefix: writePrefix,
|
|
233
|
-
nextFunctionId: nextFunctionIdFactory(),
|
|
234
228
|
deadlineMs: () => stepDeadlineMs,
|
|
235
229
|
lineageCollector,
|
|
236
230
|
blockerHolder,
|
|
@@ -251,15 +245,17 @@ export async function runSandboxStepBody(input, deps) {
|
|
|
251
245
|
// `tool-finished`) and model-output deltas are wrapped under the
|
|
252
246
|
// `data-loop-event` envelope so the SSE consumer can route them.
|
|
253
247
|
//
|
|
254
|
-
// Every emit is `await`ed in
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
248
|
+
// Every emit is `await`ed in order (the loop awaits its own emits, and the
|
|
249
|
+
// exec awaits its sandbox-event emits). A body-path `DBOS.writeStream` lands
|
|
250
|
+
// at a deterministic function-ID on replay (see the harness-durable-runtime
|
|
251
|
+
// spec) — no fire-and-forget tail racing the next real op for the counter.
|
|
252
|
+
// A sandbox event arrives from inside the step of its tool call; a write from
|
|
253
|
+
// a step takes no function-ID, and a recovered step writes its events again.
|
|
254
|
+
// `safeEmit` swallows a stream-write failure: a dropped UI frame is
|
|
255
|
+
// non-fatal and must not fail the step.
|
|
260
256
|
// Pattern A (fan-in at route): write to the CHILD's own `"events"` stream.
|
|
261
|
-
// `DBOS.writeStream`
|
|
262
|
-
//
|
|
257
|
+
// `DBOS.writeStream` writes only to the stream of its own workflow, so the
|
|
258
|
+
// SSE route reads the parent's stream plus every active child's, addressed
|
|
263
259
|
// by `cortex_step_executions.child_workflow_id`.
|
|
264
260
|
const emitToParentStream = (part) => DBOS.writeStream("events", part);
|
|
265
261
|
const safeEmit = async (part) => {
|
|
@@ -328,9 +324,10 @@ export async function runSandboxStepBody(input, deps) {
|
|
|
328
324
|
// of the step) and emits the FULL tree under a stable per-step reconciling
|
|
329
325
|
// id — the terminal `walkArtifacts` tree reconciles onto the same id at step
|
|
330
326
|
// end. Full-tree + reconciling means an observer reconnecting from offset 0
|
|
331
|
-
// still converges (raw deltas alone would not).
|
|
332
|
-
//
|
|
333
|
-
//
|
|
327
|
+
// still converges (raw deltas alone would not). The fold is live view only:
|
|
328
|
+
// a replayed tool call returns its cached result and folds no delta, thus
|
|
329
|
+
// after a recovery the live tree holds the deltas of the later execs until
|
|
330
|
+
// the terminal tree reconciles it.
|
|
334
331
|
const treeFileId = stepPartId("step-file-tree", input.runId, input.stepId);
|
|
335
332
|
const treeFiles = new Set();
|
|
336
333
|
const emitFileTree = () => safeEmit({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inflexa-ai/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "Host-agnostic bioinformatics agent harness — hand-rolled agent loop, DBOS-durable workflows, sandboxed compute.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,8 +35,10 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsc -p tsconfig.json && node scripts/copy-assets.mjs",
|
|
37
37
|
"design:fixture": "bun scripts/render-fixture.ts",
|
|
38
|
+
"design:gallery": "bun scripts/render-gallery.ts",
|
|
38
39
|
"format": "prettier --write src/",
|
|
39
40
|
"format:file": "prettier --write",
|
|
41
|
+
"gallery:data": "bash scripts/gallery-data.sh",
|
|
40
42
|
"lint": "eslint .",
|
|
41
43
|
"lint:python": "ruff check src/input-scan/decoder && ruff format --check src/input-scan/decoder",
|
|
42
44
|
"prepare": "tsc -p tsconfig.json && node scripts/copy-assets.mjs",
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `awaitExec` — awaits a submitted exec's terminal result, forwarding progress
|
|
3
|
-
* events, under one of two transports selected by `options.transport`:
|
|
4
|
-
*
|
|
5
|
-
* - `poll` (default): {@link awaitExecPoll} loops durable pull steps against
|
|
6
|
-
* `GET /exec/{execId}?since={cursor}`. The sandbox initiates nothing; the
|
|
7
|
-
* host asks. Inherently restart-proof — a recovered workflow just resumes
|
|
8
|
-
* polling from its current identity — so the recovery wedge (#41) does not
|
|
9
|
-
* apply. A machine that dies mid-exec fast-fails in-loop: sustained
|
|
10
|
-
* `unavailable` polls escalate to a backend-inspect probe (`liveness.ts`)
|
|
11
|
-
* and an observably dead machine returns the synthetic-failure result
|
|
12
|
-
* instead of waiting out the deadline.
|
|
13
|
-
* - `callback`: {@link awaitExecCallback} is the recv loop below, with the
|
|
14
|
-
* pull as its recovery backstop.
|
|
15
|
-
*
|
|
16
|
-
* Both run in the workflow body (NOT a step) — `DBOS.recv`, `DBOS.writeStream`,
|
|
17
|
-
* and `DBOS.sleepms` are body-only — and both verify every result against the
|
|
18
|
-
* per-sandbox HMAC, treating a bad/stale signature as a hard cancel.
|
|
19
|
-
*
|
|
20
|
-
* ## Callback mode: the recv loop
|
|
21
|
-
*
|
|
22
|
-
* On each received envelope:
|
|
23
|
-
*
|
|
24
|
-
* 1. If it carries `signature: null` and the payload is a
|
|
25
|
-
* `synthetic-failure` done-marker, accept it — the watchdog is an
|
|
26
|
-
* in-process trusted sender. Any other null-signature message
|
|
27
|
-
* hard-cancels.
|
|
28
|
-
* 2. Otherwise HMAC-verify against the per-sandbox `callbackSecret`.
|
|
29
|
-
* A bad or stale signature throws `HardCancelError`, which DBOS
|
|
30
|
-
* treats as a fatal workflow error (no retry).
|
|
31
|
-
* 3. If the verified payload is a done-marker, return its `result`.
|
|
32
|
-
* 4. Otherwise forward the payload via `emit` and continue.
|
|
33
|
-
*
|
|
34
|
-
* `deadline` is an absolute unix-ms timestamp — the durable backstop
|
|
35
|
-
* (typically `step.timeout`). `T` is liveness-agnostic recv pacing: we
|
|
36
|
-
* use `min(5s, remaining)` so the loop returns often enough to honour
|
|
37
|
-
* the deadline.
|
|
38
|
-
*
|
|
39
|
-
* ## Recv is not the only way home
|
|
40
|
-
*
|
|
41
|
-
* The completion callback is a *push* to an address baked into the container at
|
|
42
|
-
* creation. A host that dies mid-exec comes back with a different ingress port,
|
|
43
|
-
* so the push can never land — the sandbox retries into a void while the
|
|
44
|
-
* recovered recv waits for a message that will never arrive. That is the
|
|
45
|
-
* recovery wedge (#41), and it is silent: a `running` row that never advances.
|
|
46
|
-
*
|
|
47
|
-
* So whenever the topic falls quiet, this loop stops waiting and *asks*:
|
|
48
|
-
* `GET /exec/{execId}` on the sandbox itself returns the terminal result,
|
|
49
|
-
* signed fresh at request time. The bytes are the ones the callback would have
|
|
50
|
-
* carried, so the provenance frame survives the recovery path intact and one
|
|
51
|
-
* verification path serves both. Push remains the fast path; pull is what makes
|
|
52
|
-
* the protocol durable rather than merely optimistic.
|
|
53
|
-
*
|
|
54
|
-
* The pull is a DBOS step, not a bare `fetch`: a body-level call whose result
|
|
55
|
-
* varied between replays would desynchronise the recorded function-ID sequence.
|
|
56
|
-
*/
|
|
57
|
-
import { type ExecEmit, type ExecResult, type SandboxLiveness, type SandboxRef, type SandboxTransport } from "./types.js";
|
|
58
|
-
export declare class HardCancelError extends Error {
|
|
59
|
-
readonly execId: string;
|
|
60
|
-
readonly reason: "bad-signature" | "stale-timestamp" | "missing" | "synthetic-without-marker";
|
|
61
|
-
constructor(execId: string, reason: "bad-signature" | "stale-timestamp" | "missing" | "synthetic-without-marker", detail?: string);
|
|
62
|
-
}
|
|
63
|
-
export declare class ExecTimeoutError extends Error {
|
|
64
|
-
readonly execId: string;
|
|
65
|
-
constructor(execId: string);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Dependency seams of the await loops — every member is an injectable effect
|
|
69
|
-
* (clock, recv, fetch, durable step, durable sleep, warn sink) plus the
|
|
70
|
-
* transport selector. Tuning values (freshness window, pull threshold, poll
|
|
71
|
-
* cadence) are module constants, not options.
|
|
72
|
-
*/
|
|
73
|
-
export interface AwaitExecOptions {
|
|
74
|
-
/**
|
|
75
|
-
* Clock source for the deadline check and HMAC freshness. Defaults to the
|
|
76
|
-
* checkpointed `DBOS.now()` so the loop's recv count is replay-stable (a raw
|
|
77
|
-
* `Date.now()` here drifts the recorded `DBOS.recv` function-ID sequence on
|
|
78
|
-
* recovery — see the harness-durable-runtime spec).
|
|
79
|
-
*/
|
|
80
|
-
now?: () => number | Promise<number>;
|
|
81
|
-
/** Replaces `DBOS.recv` (callback mode). */
|
|
82
|
-
recv?: <T>(topic: string, timeoutSec: number) => Promise<T | null>;
|
|
83
|
-
/** Defaults to `globalThis.fetch`. */
|
|
84
|
-
fetch?: typeof fetch;
|
|
85
|
-
/** Defaults to `DBOS.runStep`. */
|
|
86
|
-
runStep?: <T>(fn: () => Promise<T>, config: {
|
|
87
|
-
name: string;
|
|
88
|
-
}) => Promise<T>;
|
|
89
|
-
/**
|
|
90
|
-
* Result transport. `poll` (default) runs the durable poll loop; `callback`
|
|
91
|
-
* runs the `DBOS.recv` loop with the pull as its recovery backstop. The
|
|
92
|
-
* composition root passes the same value it hands the container.
|
|
93
|
-
*/
|
|
94
|
-
transport?: SandboxTransport;
|
|
95
|
-
/** Replaces the durable inter-poll sleep. Defaults to `DBOS.sleepms`. */
|
|
96
|
-
sleep?: (ms: number) => Promise<void>;
|
|
97
|
-
/**
|
|
98
|
-
* Sink for advisory warnings (poll-mode progress-event loss). Defaults to
|
|
99
|
-
* `DBOS.logger.warn`. Advisory only: the terminal result — not the event
|
|
100
|
-
* stream — is the authoritative outcome.
|
|
101
|
-
*/
|
|
102
|
-
warn?: (message: string) => void;
|
|
103
|
-
/**
|
|
104
|
-
* Backend inspect for the poll loop's liveness escalation (`liveness.ts`).
|
|
105
|
-
* Wired by `createSandboxClient` from its backend ops; when absent the
|
|
106
|
-
* loop skips escalation and stays purely deadline-bounded. Throws on
|
|
107
|
-
* transient backend API errors — the escalation treats a throw as an
|
|
108
|
-
* inconclusive probe, never a failed exec.
|
|
109
|
-
*/
|
|
110
|
-
isAlive?: (ref: SandboxRef) => Promise<SandboxLiveness>;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Await a submitted exec's terminal result. Dispatches on transport — `poll`
|
|
114
|
-
* (default) or `callback`. Both verify every result against the per-sandbox
|
|
115
|
-
* HMAC and are bounded by `deadlineMs`.
|
|
116
|
-
*/
|
|
117
|
-
export declare function awaitExec(ref: SandboxRef, execId: string, emit: ExecEmit, deadlineMs: number, options?: AwaitExecOptions): Promise<ExecResult>;
|
|
118
|
-
/**
|
|
119
|
-
* Body of the recv loop (callback transport). Hoisted so it's testable without
|
|
120
|
-
* spinning up DBOS — `recv` is injectable and `now` is overridable.
|
|
121
|
-
*/
|
|
122
|
-
export declare function awaitExecCallback(ref: SandboxRef, execId: string, emit: ExecEmit, deadlineMs: number, options?: AwaitExecOptions): Promise<ExecResult>;
|
|
123
|
-
/**
|
|
124
|
-
* Body of the poll loop (poll transport). No `DBOS.recv`, no per-exec topic, no
|
|
125
|
-
* callback handler: a sequence of durable pull steps named
|
|
126
|
-
* `sandbox.poll-exec-result.${execId}.${n}`, each fetching the signed
|
|
127
|
-
* `{ status, events, cursor, result? }`, verifying it exactly as a pushed
|
|
128
|
-
* completion is verified, forwarding new events via `emit`, advancing the
|
|
129
|
-
* cursor, and returning `result` once terminal. `sleep`, `now`, `fetch`,
|
|
130
|
-
* `runStep`, and `isAlive` are injectable so the loop is testable without DBOS.
|
|
131
|
-
*
|
|
132
|
-
* Liveness: when the `isAlive` seam is wired (the client always wires it),
|
|
133
|
-
* consecutive `unavailable` polls past the module threshold escalate to a
|
|
134
|
-
* durable probe step `sandbox.probe-liveness.${execId}.${k}`; a dead verdict
|
|
135
|
-
* returns the synthetic-failure result in-loop — the poll-mode analogue of the
|
|
136
|
-
* watchdog's synthetic-complete, minus the topic and the race gate, since the
|
|
137
|
-
* verdict is produced and consumed by the same workflow in sequence.
|
|
138
|
-
*
|
|
139
|
-
* The `cursor`, `pollAttempt`, and `probeAttempt` counters are pure functions
|
|
140
|
-
* of the cached step sequence, so a replay issues the same polls and probes in
|
|
141
|
-
* the same order and the DBOS function-ID sequence stays stable.
|
|
142
|
-
*/
|
|
143
|
-
export declare function awaitExecPoll(ref: SandboxRef, execId: string, emit: ExecEmit, deadlineMs: number, options?: AwaitExecOptions): Promise<ExecResult>;
|