@inflexa-ai/harness 0.37.0 → 0.39.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 +1 -2
- package/dist/auth/local-run-authorizer.js +5 -4
- package/dist/auth/types.d.ts +28 -9
- package/dist/auth/types.js +5 -3
- package/dist/billing/cached-resolver.d.ts +11 -7
- package/dist/billing/cached-resolver.js +17 -11
- package/dist/billing/noop-run-charge.js +3 -2
- package/dist/billing/noop-usage-recorder.js +2 -1
- package/dist/billing/run-charge.d.ts +18 -5
- package/dist/billing/run-charge.js +5 -1
- package/dist/billing/usage-recorder.d.ts +11 -9
- package/dist/billing/usage-recorder.js +2 -3
- package/dist/contracts/chat-events.d.ts +4 -1
- package/dist/contracts/chat-parts.d.ts +1 -1
- package/dist/contracts/schemas/chat-parts.d.ts +4 -4
- package/dist/execution/artifact-registration.d.ts +6 -1
- package/dist/execution/artifact-registration.js +12 -4
- package/dist/execution/artifact-registry.d.ts +10 -3
- package/dist/execution/noop-artifact-registry.js +3 -4
- package/dist/execution/post-step-pipeline.d.ts +14 -3
- package/dist/execution/post-step-pipeline.js +21 -8
- package/dist/execution/run-authorizer.d.ts +5 -3
- package/dist/execution/run-canceler.js +4 -20
- package/dist/index.d.ts +14 -8
- package/dist/index.js +12 -6
- package/dist/lib/hooks.d.ts +49 -0
- package/dist/lib/hooks.js +39 -0
- package/dist/lib/result.d.ts +22 -11
- package/dist/lib/result.js +24 -14
- package/dist/loop/run-agent.d.ts +2 -2
- package/dist/loop/run-agent.js +5 -4
- package/dist/provenance/seam.d.ts +1 -1
- package/dist/providers/ai-sdk.d.ts +43 -5
- package/dist/providers/ai-sdk.js +55 -52
- package/dist/providers/anthropic.d.ts +2 -3
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/embedding.d.ts +13 -7
- package/dist/providers/embedding.js +26 -6
- package/dist/providers/errors.d.ts +67 -37
- package/dist/providers/errors.js +57 -58
- package/dist/providers/request-headers.d.ts +18 -0
- package/dist/providers/request-headers.js +22 -0
- package/dist/report-model/production-resolver.d.ts +5 -2
- package/dist/report-model/production-resolver.js +12 -2
- package/dist/runtime/assemble.d.ts +3 -2
- package/dist/runtime/dbos.d.ts +4 -3
- package/dist/runtime/dbos.js +18 -3
- package/dist/runtime/result-serialization.d.ts +29 -0
- package/dist/runtime/result-serialization.js +45 -0
- package/dist/sandbox/client.d.ts +11 -3
- package/dist/sandbox/create-sandbox.d.ts +5 -2
- package/dist/sandbox/create-sandbox.js +51 -25
- package/dist/sandbox/docker-client.d.ts +4 -3
- package/dist/sandbox/docker-client.js +23 -31
- package/dist/sandbox/k8s-client.d.ts +4 -13
- package/dist/sandbox/k8s-client.js +28 -61
- package/dist/sandbox/labels.d.ts +34 -0
- package/dist/sandbox/labels.js +47 -0
- package/dist/sandbox/mount-plan.d.ts +3 -1
- package/dist/sandbox/mount-plan.js +9 -0
- package/dist/sandbox/sandbox-error.d.ts +36 -13
- package/dist/sandbox/sandbox-error.js +32 -17
- package/dist/sandbox/types.d.ts +18 -10
- package/dist/schemas/validate-plan.js +13 -0
- package/dist/schemas/workflow-state.d.ts +4 -4
- package/dist/state/analyses.d.ts +4 -4
- package/dist/state/analyses.js +4 -4
- package/dist/state/schema.d.ts +5 -5
- package/dist/tasks/data-profile.d.ts +5 -8
- package/dist/tasks/data-profile.js +88 -43
- package/dist/tasks/derive-table-exec.d.ts +10 -6
- package/dist/tasks/derive-table-exec.js +17 -12
- package/dist/tasks/extract-values.d.ts +16 -10
- package/dist/tasks/extract-values.js +34 -18
- package/dist/tools/execute-analysis.js +29 -24
- package/dist/tools/report-session/derive-table.d.ts +9 -1
- package/dist/tools/report-session/derive-table.js +25 -22
- package/dist/tools/report-session/examine-page.d.ts +6 -3
- package/dist/tools/report-session/examine-page.js +16 -8
- package/dist/tools/report-session/index.d.ts +1 -1
- package/dist/tools/report-session/preview-report.js +11 -9
- package/dist/tools/report-session/session-page-publisher.d.ts +17 -21
- package/dist/tools/report-session/session-page-publisher.js +5 -7
- package/dist/tools/research/inspect-run.d.ts +1 -1
- package/dist/tools/sandbox/link-packages.d.ts +8 -0
- package/dist/tools/sandbox/link-packages.js +19 -9
- package/dist/workflows/execute-analysis.d.ts +25 -16
- package/dist/workflows/execute-analysis.js +223 -216
- package/dist/workflows/metrics.d.ts +4 -3
- package/dist/workflows/metrics.js +4 -3
- package/dist/workflows/sandbox-step.d.ts +20 -29
- package/dist/workflows/sandbox-step.js +71 -127
- package/dist/workflows/suspension.d.ts +32 -0
- package/dist/workflows/suspension.js +38 -0
- package/package.json +1 -1
- package/dist/billing/noop-resolver.d.ts +0 -6
- package/dist/billing/noop-resolver.js +0 -7
- package/dist/billing/resolver.d.ts +0 -64
- package/dist/billing/resolver.js +0 -24
- package/dist/loop/budget-exceeded.d.ts +0 -38
- package/dist/loop/budget-exceeded.js +0 -88
|
@@ -350,7 +350,7 @@ async function sweepAssets(assetsDir, staged, logger) {
|
|
|
350
350
|
*
|
|
351
351
|
* An absent factory gives no grant, and the arm carries no access field — the page path stays the whole
|
|
352
352
|
* local contract. The tool builds the publisher over the scope of the call, thus the mint runs under the
|
|
353
|
-
* auth of the caller.
|
|
353
|
+
* auth of the caller. An `err`, a thrown construction, and a rejected realization each become the
|
|
354
354
|
* not-granted arm, thus a broken grant surface never costs the render. The URL spells through
|
|
355
355
|
* `buildReportSessionUrl`, thus the formula lives in the contract and the seam gives the content-server
|
|
356
356
|
* base alone.
|
|
@@ -359,22 +359,24 @@ async function mintAccess(makeSessionPages, analysisId, threadId, auth, logger)
|
|
|
359
359
|
if (makeSessionPages === undefined) {
|
|
360
360
|
return undefined;
|
|
361
361
|
}
|
|
362
|
-
let
|
|
362
|
+
let grant;
|
|
363
363
|
try {
|
|
364
|
-
minted = await makeSessionPages({ analysisId, auth }).mintSessionPageAccess(threadId);
|
|
364
|
+
const minted = await makeSessionPages({ analysisId, auth }).mintSessionPageAccess(threadId);
|
|
365
|
+
if (minted.isErr()) {
|
|
366
|
+
const detail = describeSessionPageMintFailure(minted.error);
|
|
367
|
+
logger.warn("the session-page mint refused", { threadId, analysisId, detail });
|
|
368
|
+
return { granted: false, detail };
|
|
369
|
+
}
|
|
370
|
+
grant = minted.value;
|
|
365
371
|
}
|
|
366
372
|
catch (cause) {
|
|
367
373
|
logger.warn("the session-page mint threw", { threadId, analysisId, ...defaultErrorFields(cause) });
|
|
368
374
|
return { granted: false, detail: "session-page-access mint failed" };
|
|
369
375
|
}
|
|
370
|
-
if (!minted.ok) {
|
|
371
|
-
logger.warn("the session-page mint refused", { threadId, analysisId, detail: describeSessionPageMintFailure(minted) });
|
|
372
|
-
return { granted: false, detail: describeSessionPageMintFailure(minted) };
|
|
373
|
-
}
|
|
374
376
|
return {
|
|
375
377
|
granted: true,
|
|
376
|
-
url: buildReportSessionUrl(
|
|
377
|
-
expiresAt:
|
|
378
|
+
url: buildReportSessionUrl(grant.baseUrl, analysisId, threadId, "index.html", grant.token),
|
|
379
|
+
expiresAt: grant.expiresAt,
|
|
378
380
|
};
|
|
379
381
|
}
|
|
380
382
|
/**
|
|
@@ -11,28 +11,24 @@
|
|
|
11
11
|
* tool call, thus the composition binds a factory and the preview tool builds the publisher over the
|
|
12
12
|
* scope of the call — exactly as it builds the reference resolver. A boot-time singleton could not
|
|
13
13
|
* carry that credential, and a host that bans ambient state could not bind one at all. The local
|
|
14
|
-
* default (`UnavailableSessionPagePublisher`)
|
|
14
|
+
* default (`UnavailableSessionPagePublisher`) gives an `err`, thus the preview tool attaches no URL
|
|
15
15
|
* and the render still lands — the page path stays the whole local contract.
|
|
16
16
|
*/
|
|
17
|
+
import { type ResultAsync } from "neverthrow";
|
|
17
18
|
import type { AuthContext } from "../../auth/types.js";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
message?: string;
|
|
19
|
+
/** The grant of one session page: the content-server base, the token, and its expiry. */
|
|
20
|
+
export interface SessionPageGrant {
|
|
21
|
+
readonly baseUrl: string;
|
|
22
|
+
readonly token: string;
|
|
23
|
+
readonly expiresAt: string;
|
|
24
|
+
}
|
|
25
|
+
/** What a failed mint is allowed to carry. */
|
|
26
|
+
export interface SessionPageMintFailure {
|
|
27
|
+
readonly status?: number;
|
|
28
|
+
readonly error: {
|
|
29
|
+
readonly message?: string;
|
|
30
30
|
};
|
|
31
|
-
}
|
|
32
|
-
/** The not-ok arm of the seam's result — what a failed mint is allowed to carry. */
|
|
33
|
-
export type SessionPageMintFailure = Extract<SessionPageMintResult, {
|
|
34
|
-
ok: false;
|
|
35
|
-
}>;
|
|
31
|
+
}
|
|
36
32
|
/**
|
|
37
33
|
* Renders a failed mint as the line an agent reads back from the preview tool.
|
|
38
34
|
*
|
|
@@ -49,7 +45,7 @@ export interface SessionPagePublisher {
|
|
|
49
45
|
* caller spells the whole URL through `buildReportSessionUrl`, thus the formula lives in the
|
|
50
46
|
* contract and never in a realization.
|
|
51
47
|
*/
|
|
52
|
-
mintSessionPageAccess(threadId: string):
|
|
48
|
+
mintSessionPageAccess(threadId: string): ResultAsync<SessionPageGrant, SessionPageMintFailure>;
|
|
53
49
|
}
|
|
54
50
|
/**
|
|
55
51
|
* The per-call construction of the publisher. The factory binds one analysis and the auth of the tool
|
|
@@ -60,9 +56,9 @@ export type MakeSessionPagePublisher = (scope: {
|
|
|
60
56
|
auth: AuthContext;
|
|
61
57
|
}) => SessionPagePublisher;
|
|
62
58
|
/**
|
|
63
|
-
* Local default — no hosted view of a session page.
|
|
59
|
+
* Local default — no hosted view of a session page. Gives an `err`, thus the preview tool carries the
|
|
64
60
|
* refusal as data and the page path stays the whole result.
|
|
65
61
|
*/
|
|
66
62
|
export declare class UnavailableSessionPagePublisher implements SessionPagePublisher {
|
|
67
|
-
mintSessionPageAccess(_threadId: string):
|
|
63
|
+
mintSessionPageAccess(_threadId: string): ResultAsync<SessionPageGrant, SessionPageMintFailure>;
|
|
68
64
|
}
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
* tool call, thus the composition binds a factory and the preview tool builds the publisher over the
|
|
12
12
|
* scope of the call — exactly as it builds the reference resolver. A boot-time singleton could not
|
|
13
13
|
* carry that credential, and a host that bans ambient state could not bind one at all. The local
|
|
14
|
-
* default (`UnavailableSessionPagePublisher`)
|
|
14
|
+
* default (`UnavailableSessionPagePublisher`) gives an `err`, thus the preview tool attaches no URL
|
|
15
15
|
* and the render still lands — the page path stays the whole local contract.
|
|
16
16
|
*/
|
|
17
|
+
import { errAsync } from "neverthrow";
|
|
17
18
|
/**
|
|
18
19
|
* Renders a failed mint as the line an agent reads back from the preview tool.
|
|
19
20
|
*
|
|
@@ -32,14 +33,11 @@ export function describeSessionPageMintFailure(failure) {
|
|
|
32
33
|
return detail.length > 0 ? `session-page-access mint failed: ${detail.join(" ")}` : "session-page-access mint failed";
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
|
-
* Local default — no hosted view of a session page.
|
|
36
|
+
* Local default — no hosted view of a session page. Gives an `err`, thus the preview tool carries the
|
|
36
37
|
* refusal as data and the page path stays the whole result.
|
|
37
38
|
*/
|
|
38
39
|
export class UnavailableSessionPagePublisher {
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
ok: false,
|
|
42
|
-
error: { message: "the hosted view of a session page is unavailable in this environment" },
|
|
43
|
-
};
|
|
40
|
+
mintSessionPageAccess(_threadId) {
|
|
41
|
+
return errAsync({ error: { message: "the hosted view of a session page is unavailable in this environment" } });
|
|
44
42
|
}
|
|
45
43
|
}
|
|
@@ -53,7 +53,7 @@ declare function formatRun(r: CortexRunRow, verbose: boolean, exposePaths?: bool
|
|
|
53
53
|
synthesisReason?: string | undefined;
|
|
54
54
|
runId: string;
|
|
55
55
|
workflowName: string;
|
|
56
|
-
status: "
|
|
56
|
+
status: "failed" | "running" | "completed" | "partial" | "canceled" | "suspended_insufficient_funds";
|
|
57
57
|
startedAt: string;
|
|
58
58
|
completedAt: string | null;
|
|
59
59
|
planId: string | null;
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* capability, thus the agent learns one grammar for the plan, the tool, and
|
|
14
14
|
* the prompt layer.
|
|
15
15
|
*/
|
|
16
|
+
import { type Result } from "neverthrow";
|
|
17
|
+
import { type PackageQuery } from "../../sandbox/package-identity.js";
|
|
16
18
|
import type { ExtendAnalysisFarm, PackageRequestOutcome } from "../../sandbox/types.js";
|
|
17
19
|
export interface LinkPackagesDeps {
|
|
18
20
|
readonly extendAnalysisFarm: ExtendAnalysisFarm;
|
|
@@ -22,6 +24,12 @@ export interface LinkPackagesDeps {
|
|
|
22
24
|
export interface LinkPackagesResult {
|
|
23
25
|
readonly outcomes: readonly PackageRequestOutcome[];
|
|
24
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Call the seam, and give the outcomes or the one reason that the call gave
|
|
29
|
+
* no answer. An `err` and a rejected realization each give that reason, thus
|
|
30
|
+
* no call site sees a throw.
|
|
31
|
+
*/
|
|
32
|
+
export declare function callExtendAnalysisFarm(extendAnalysisFarm: ExtendAnalysisFarm, analysisId: string, queries: readonly PackageQuery[]): Promise<Result<readonly PackageRequestOutcome[], string>>;
|
|
25
33
|
export declare function createLinkPackagesTool(deps: LinkPackagesDeps): import("../define-tool.js").Tool<{
|
|
26
34
|
packages: string[];
|
|
27
35
|
}, LinkPackagesResult>;
|
|
@@ -34,6 +34,19 @@ function describeParseError(entry, error) {
|
|
|
34
34
|
return `"${entry}" pins with the specifier "${error.specifier}", which this tool cannot honor — pass a bare name, or name==version with one exact version`;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Call the seam, and give the outcomes or the one reason that the call gave
|
|
39
|
+
* no answer. An `err` and a rejected realization each give that reason, thus
|
|
40
|
+
* no call site sees a throw.
|
|
41
|
+
*/
|
|
42
|
+
export async function callExtendAnalysisFarm(extendAnalysisFarm, analysisId, queries) {
|
|
43
|
+
try {
|
|
44
|
+
return (await extendAnalysisFarm(analysisId, queries)).mapErr((failure) => failure.reason);
|
|
45
|
+
}
|
|
46
|
+
catch (cause) {
|
|
47
|
+
return err(cause instanceof Error ? cause.message : String(cause));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
37
50
|
export function createLinkPackagesTool(deps) {
|
|
38
51
|
return defineTool({
|
|
39
52
|
id: "link_packages",
|
|
@@ -67,17 +80,14 @@ export function createLinkPackagesTool(deps) {
|
|
|
67
80
|
}
|
|
68
81
|
queries.push(parsed.value);
|
|
69
82
|
}
|
|
70
|
-
// A
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
return ok({ outcomes });
|
|
76
|
-
}
|
|
77
|
-
catch (cause) {
|
|
78
|
-
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
83
|
+
// A call that gave no answer reads as `unavailable` per query. A
|
|
84
|
+
// raw tool error teaches the agent nothing that `reason` does not.
|
|
85
|
+
const linked = await callExtendAnalysisFarm(deps.extendAnalysisFarm, deps.analysisId, queries);
|
|
86
|
+
if (linked.isErr()) {
|
|
87
|
+
const reason = linked.error;
|
|
79
88
|
return ok({ outcomes: queries.map((query) => ({ kind: "unavailable", spelling: query.spelling, reason })) });
|
|
80
89
|
}
|
|
90
|
+
return ok({ outcomes: linked.value });
|
|
81
91
|
},
|
|
82
92
|
});
|
|
83
93
|
}
|
|
@@ -31,23 +31,30 @@
|
|
|
31
31
|
* - await child results via `getResult` (these are themselves cached
|
|
32
32
|
* in DBOS, so parent recovery does NOT re-run completed children)
|
|
33
33
|
* 3. Failure isolation
|
|
34
|
-
* - a child settling `failed`/`blocked` (or throwing for a
|
|
35
|
-
*
|
|
36
|
-
* dependency-satisfied, are marked `skipped` on the dag-state
|
|
37
|
-
* are never dispatched. In-flight siblings and independent
|
|
38
|
-
* continue; the loop drains and the run finalises (typically
|
|
34
|
+
* - a child settling `failed`/`blocked` (or throwing for a cause that is
|
|
35
|
+
* not a suspension) dooms only its transitive dependents: they can never
|
|
36
|
+
* become dependency-satisfied, are marked `skipped` on the dag-state
|
|
37
|
+
* part, and are never dispatched. In-flight siblings and independent
|
|
38
|
+
* ready steps continue; the loop drains and the run finalises (typically
|
|
39
|
+
* `partial`).
|
|
39
40
|
* - the halt cascade (cancel in-flight via
|
|
40
41
|
* `Promise.allSettled(handles.map(h => DBOS.cancelWorkflow(h.workflowID)))`,
|
|
41
|
-
* stop scheduling) survives only for
|
|
42
|
-
* `
|
|
43
|
-
* 4.
|
|
44
|
-
* -
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
* stop scheduling) survives only for a suspension of a child and the
|
|
43
|
+
* `neverFits` plan-validation guard.
|
|
44
|
+
* 4. Suspension cascade (workflow-suspension spec)
|
|
45
|
+
* - a child that suspends sends a typed message on `CHILD_SUSPENDED_TOPIC`
|
|
46
|
+
* and cancels itself. The parent reads the kind of the message, never a
|
|
47
|
+
* reason string: it cancels the siblings, then self-cancels to
|
|
48
|
+
* `CANCELLED` (NOT `ERROR` — ERROR isn't resumable; NOTES #3)
|
|
49
|
+
* - a refusal of the `RunCharge.open` gate with the suspend flag suspends
|
|
50
|
+
* the run before any step starts
|
|
51
|
+
* - a `suspend` error of a synthesis model request suspends the run in
|
|
52
|
+
* place of the synthesis failure
|
|
47
53
|
* - the analysis flips to `suspended_insufficient_funds` in
|
|
48
54
|
* `collectAndComplete`. The paused parent lands in `CANCELLED`, a
|
|
49
|
-
* durably reschedulable state; re-driving it
|
|
50
|
-
*
|
|
55
|
+
* durably reschedulable state; re-driving it is a future enhancement,
|
|
56
|
+
* not yet wired here. The reason of the host rides to the run row, the
|
|
57
|
+
* charge close, the metric, and the terminal part, unread.
|
|
51
58
|
* 5. `synthesizeFindings` (single sequential block, no sandbox)
|
|
52
59
|
* 6. `collectAndComplete` (terminal — runs on ALL paths)
|
|
53
60
|
* - determine final status from completed/cancelled/failed counts
|
|
@@ -77,6 +84,7 @@ import type { RunCharge } from "../billing/run-charge.js";
|
|
|
77
84
|
import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
|
|
78
85
|
import { type PlanStep } from "./execute-analysis-scheduler.js";
|
|
79
86
|
import { type SandboxStepInput, type SandboxStepResult } from "./sandbox-step.js";
|
|
87
|
+
import { type Suspension } from "./suspension.js";
|
|
80
88
|
/** Registered child sandbox-step callable the parent's child-dispatch closes over. */
|
|
81
89
|
type SandboxStepCallable = (input: SandboxStepInput) => Promise<SandboxStepResult>;
|
|
82
90
|
/** Quick-display finding on the run-completed card. Mirrors the wire schema's RunCompletedFinding. */
|
|
@@ -320,13 +328,14 @@ export declare function composeStepSeed(args: {
|
|
|
320
328
|
* its reason in `blockedReason` — an honest agent-declared blocker, not an
|
|
321
329
|
* error — and a failure carries the same reason string
|
|
322
330
|
* `persist-synthesis-outcome` writes to `cortex_runs.synthesis_reason`, so the
|
|
323
|
-
* two ledgers cannot disagree about why synthesis died.
|
|
324
|
-
*
|
|
331
|
+
* two ledgers cannot disagree about why synthesis died. A suspension is not an
|
|
332
|
+
* outcome: the row is canceled, as the row of a suspended step. Exported for
|
|
333
|
+
* the projection tests (the `buildChildInput` pattern).
|
|
325
334
|
*/
|
|
326
335
|
export declare function synthesisRowUpdate(outcome: {
|
|
327
336
|
status: SynthesisStatus;
|
|
328
337
|
reason: string | null;
|
|
329
|
-
}, durationMs: number): UpdateStepExecutionInput;
|
|
338
|
+
} | Suspension, durationMs: number): UpdateStepExecutionInput;
|
|
330
339
|
/**
|
|
331
340
|
* Run-level literature-grounded synthesis (no sandbox). Returns the
|
|
332
341
|
* quick-display findings for the run-completed card; empty when synthesis is
|