@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
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
* callback unroutable and it lands as a `400`. The pull backstop still settles such an exec, but it pays
|
|
19
19
|
* the quiet interval first.
|
|
20
20
|
*/
|
|
21
|
+
import { type Result } from "neverthrow";
|
|
21
22
|
import type { Logger } from "../lib/logger.js";
|
|
22
23
|
import type { SandboxClient } from "../sandbox/client.js";
|
|
24
|
+
import { type Suspension } from "../workflows/suspension.js";
|
|
23
25
|
import type { ExecResult } from "../sandbox/types.js";
|
|
24
26
|
import { type DeriveTableExecInput } from "../tools/report-session/derive-table.js";
|
|
25
27
|
/** The construction-time deps of the body. The registration closes over them, thus the trigger holds none. */
|
|
@@ -35,15 +37,17 @@ export interface DeriveTableExecDeps {
|
|
|
35
37
|
/**
|
|
36
38
|
* The body, exported so a test drives it without a registered workflow.
|
|
37
39
|
*
|
|
38
|
-
* A fault of any seam call throws. The tool reads a rejection as one short detail
|
|
39
|
-
* result
|
|
40
|
+
* A fault of any seam call throws. The tool reads a rejection as one short detail. A chat turn awaits this
|
|
41
|
+
* workflow, thus a suspension is the `err` of the result, and the workflow does not cancel
|
|
42
|
+
* (workflow-suspension spec). The body does not mark the analysis: the tool reports the suspension to the
|
|
43
|
+
* conversation agent.
|
|
40
44
|
*/
|
|
41
|
-
export declare function runDeriveTableExecBody(input: DeriveTableExecInput, deps: DeriveTableExecDeps): Promise<ExecResult
|
|
45
|
+
export declare function runDeriveTableExecBody(input: DeriveTableExecInput, deps: DeriveTableExecDeps): Promise<Result<ExecResult, Suspension>>;
|
|
42
46
|
/**
|
|
43
47
|
* Register the derivation workflow with DBOS. It gives back the registered callable, thus a trigger
|
|
44
48
|
* dispatches with `DBOS.startWorkflow`.
|
|
45
49
|
*/
|
|
46
|
-
export declare function registerDeriveTableExecWorkflow(deps: DeriveTableExecDeps): (input: DeriveTableExecInput) => Promise<ExecResult
|
|
50
|
+
export declare function registerDeriveTableExecWorkflow(deps: DeriveTableExecDeps): (input: DeriveTableExecInput) => Promise<Result<ExecResult, Suspension>>;
|
|
47
51
|
/**
|
|
48
52
|
* The workflow id of one derivation.
|
|
49
53
|
*
|
|
@@ -55,6 +59,6 @@ export declare function deriveTableExecWorkflowId(executionId: string): string;
|
|
|
55
59
|
* The async edge. It starts the registered workflow and it awaits the terminal result.
|
|
56
60
|
*
|
|
57
61
|
* The tool authorizes the derivation before this call and it revokes after, thus this edge holds no
|
|
58
|
-
* lifecycle of its own. A workflow fault rejects the returned promise
|
|
62
|
+
* lifecycle of its own. A workflow fault rejects the returned promise, and a suspension is the `err`.
|
|
59
63
|
*/
|
|
60
|
-
export declare function triggerDeriveTableExec(workflow: (input: DeriveTableExecInput) => Promise<ExecResult
|
|
64
|
+
export declare function triggerDeriveTableExec(workflow: (input: DeriveTableExecInput) => Promise<Result<ExecResult, Suspension>>, input: DeriveTableExecInput): Promise<Result<ExecResult, Suspension>>;
|
|
@@ -19,16 +19,22 @@
|
|
|
19
19
|
* the quiet interval first.
|
|
20
20
|
*/
|
|
21
21
|
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
22
|
+
import { err, ok } from "neverthrow";
|
|
23
|
+
import { forStep } from "../auth/types.js";
|
|
22
24
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
23
25
|
import { mintSandboxIdentity } from "../sandbox/identity.js";
|
|
26
|
+
import { keepSuspendingRefusal } from "../sandbox/sandbox-error.js";
|
|
27
|
+
import { suspensionOfSpawnRefusal } from "../workflows/suspension.js";
|
|
24
28
|
import { buildDerivationExec, DERIVATION_DEADLINE_MS, DERIVATION_RESOURCES, DERIVE_RUN_LITERAL, DERIVE_STEP_LITERAL, } from "../tools/report-session/derive-table.js";
|
|
25
29
|
/** The awaitExec callback. A derivation reports no live activity, thus the callback drops each event. */
|
|
26
30
|
const noopEmit = () => { };
|
|
27
31
|
/**
|
|
28
32
|
* The body, exported so a test drives it without a registered workflow.
|
|
29
33
|
*
|
|
30
|
-
* A fault of any seam call throws. The tool reads a rejection as one short detail
|
|
31
|
-
* result
|
|
34
|
+
* A fault of any seam call throws. The tool reads a rejection as one short detail. A chat turn awaits this
|
|
35
|
+
* workflow, thus a suspension is the `err` of the result, and the workflow does not cancel
|
|
36
|
+
* (workflow-suspension spec). The body does not mark the analysis: the tool reports the suspension to the
|
|
37
|
+
* conversation agent.
|
|
32
38
|
*/
|
|
33
39
|
export async function runDeriveTableExecBody(input, deps) {
|
|
34
40
|
const logger = (deps.logger ?? createNoopLogger()).named("derive-table-exec").with({ analysisId: input.analysisId });
|
|
@@ -36,14 +42,13 @@ export async function runDeriveTableExecBody(input, deps) {
|
|
|
36
42
|
// One workflow submits one exec, thus the function id is a constant. The three segments are what a
|
|
37
43
|
// callback host parses to find the workflow that awaits this exec.
|
|
38
44
|
const execId = `${workflowId}:${DERIVE_STEP_LITERAL}:fn-0`;
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}, mintSandboxIdentity(DERIVE_RUN_LITERAL));
|
|
45
|
+
const spawned = keepSuspendingRefusal(await deps.sandboxClient.createSandbox(forStep(input.runSession, DERIVE_STEP_LITERAL), { childWorkflowId: workflowId, resources: DERIVATION_RESOURCES, writableTail: input.writableTail }, mintSandboxIdentity(DERIVE_RUN_LITERAL)));
|
|
46
|
+
if (spawned.isErr()) {
|
|
47
|
+
const suspension = suspensionOfSpawnRefusal(spawned.error);
|
|
48
|
+
logger.warn("derivation suspended", { reason: suspension.reason });
|
|
49
|
+
return err(suspension);
|
|
50
|
+
}
|
|
51
|
+
const sandbox = spawned.value;
|
|
47
52
|
try {
|
|
48
53
|
// A checkpointed clock, not `Date.now()`: the await gates on this absolute deadline, and a
|
|
49
54
|
// wall-clock deadline that grew on replay would shift which loop iteration crosses it.
|
|
@@ -55,7 +60,7 @@ export async function runDeriveTableExecBody(input, deps) {
|
|
|
55
60
|
inputs: input.inputs,
|
|
56
61
|
output: input.output,
|
|
57
62
|
}));
|
|
58
|
-
return await deps.sandboxClient.awaitExec(sandbox, execId, noopEmit, deadline);
|
|
63
|
+
return ok(await deps.sandboxClient.awaitExec(sandbox, execId, noopEmit, deadline));
|
|
59
64
|
}
|
|
60
65
|
finally {
|
|
61
66
|
try {
|
|
@@ -86,7 +91,7 @@ export function deriveTableExecWorkflowId(executionId) {
|
|
|
86
91
|
* The async edge. It starts the registered workflow and it awaits the terminal result.
|
|
87
92
|
*
|
|
88
93
|
* The tool authorizes the derivation before this call and it revokes after, thus this edge holds no
|
|
89
|
-
* lifecycle of its own. A workflow fault rejects the returned promise
|
|
94
|
+
* lifecycle of its own. A workflow fault rejects the returned promise, and a suspension is the `err`.
|
|
90
95
|
*/
|
|
91
96
|
export async function triggerDeriveTableExec(workflow, input) {
|
|
92
97
|
const handle = (await DBOS.startWorkflow(workflow, {
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
* authorization on every terminal path. The container is ephemeral, and it goes away with the work, thus no
|
|
12
12
|
* standing machine exists.
|
|
13
13
|
*/
|
|
14
|
-
import
|
|
14
|
+
import { type Result } from "neverthrow";
|
|
15
|
+
import { type AuthContext, type RunSession } from "../auth/types.js";
|
|
15
16
|
import type { RunAuthorizer } from "../execution/run-authorizer.js";
|
|
16
17
|
import type { Logger } from "../lib/logger.js";
|
|
17
18
|
import type { ExtractionArm, ExtractionArtifact, ExtractionRequest } from "../report-model/production-resolver.js";
|
|
18
19
|
import type { SandboxClient } from "../sandbox/client.js";
|
|
20
|
+
import { type Suspension } from "../workflows/suspension.js";
|
|
19
21
|
import type { ExecResult, SubmitExecBody } from "../sandbox/types.js";
|
|
20
22
|
import { type ExtractValuesResult } from "./extract-values-script.js";
|
|
21
23
|
export type { ExtractValuesResult } from "./extract-values-script.js";
|
|
@@ -71,13 +73,16 @@ export declare function parseExtractionOutput(result: ExecResult): ExtractValues
|
|
|
71
73
|
* The body, extracted so a test drives it without a registered workflow. It creates the ephemeral
|
|
72
74
|
* container, submits one exec, awaits the result durably, and gives the value map back. It revokes the run
|
|
73
75
|
* authorization on every terminal path, and it tears the container down on both paths.
|
|
76
|
+
*
|
|
77
|
+
* A chat turn awaits this workflow, thus a suspension is the `err` of the result, and the workflow does not
|
|
78
|
+
* cancel (workflow-suspension spec). The body does not mark the analysis: the caller reports the suspension.
|
|
74
79
|
*/
|
|
75
|
-
export declare function runExtractValuesBody(input: ExtractValuesWorkflowInput, deps: ExtractValuesDeps): Promise<ExtractValuesResult
|
|
80
|
+
export declare function runExtractValuesBody(input: ExtractValuesWorkflowInput, deps: ExtractValuesDeps): Promise<Result<ExtractValuesResult, Suspension>>;
|
|
76
81
|
/**
|
|
77
82
|
* Register the extraction workflow with DBOS. It gives back the registered callable, thus a trigger
|
|
78
83
|
* dispatches with `DBOS.startWorkflow`.
|
|
79
84
|
*/
|
|
80
|
-
export declare function registerExtractValuesWorkflow(deps: ExtractValuesDeps): (input: ExtractValuesWorkflowInput) => Promise<ExtractValuesResult
|
|
85
|
+
export declare function registerExtractValuesWorkflow(deps: ExtractValuesDeps): (input: ExtractValuesWorkflowInput) => Promise<Result<ExtractValuesResult, Suspension>>;
|
|
81
86
|
/** The per-attempt workflow id. A fresh nonce keeps each pass under a distinct id. */
|
|
82
87
|
export declare function extractValuesWorkflowId(analysisId: string, nonce: string): string;
|
|
83
88
|
/**
|
|
@@ -86,7 +91,7 @@ export declare function extractValuesWorkflowId(analysisId: string, nonce: strin
|
|
|
86
91
|
*/
|
|
87
92
|
export interface ExtractValuesTriggerDeps {
|
|
88
93
|
readonly runAuthorizer: RunAuthorizer;
|
|
89
|
-
readonly workflow: (input: ExtractValuesWorkflowInput) => Promise<ExtractValuesResult
|
|
94
|
+
readonly workflow: (input: ExtractValuesWorkflowInput) => Promise<Result<ExtractValuesResult, Suspension>>;
|
|
90
95
|
}
|
|
91
96
|
/** The identity and the requests for one extraction pass. */
|
|
92
97
|
export interface ExtractValuesTriggerParams {
|
|
@@ -96,12 +101,13 @@ export interface ExtractValuesTriggerParams {
|
|
|
96
101
|
}
|
|
97
102
|
/**
|
|
98
103
|
* The async edge. It authorizes through the `RunAuthorizer`, starts the workflow, and awaits the outcome.
|
|
99
|
-
* The body owns the revoke, thus the trigger holds no lifecycle. A workflow fault
|
|
100
|
-
* promise.
|
|
104
|
+
* The body owns the revoke, thus the trigger holds no lifecycle. A workflow fault and a refused
|
|
105
|
+
* authorization reject the returned promise. A suspension is the `err` of the result: of the workflow, or of
|
|
106
|
+
* an authorization that the host refused with the suspend flag.
|
|
101
107
|
*/
|
|
102
|
-
export declare function triggerExtractValues(deps: ExtractValuesTriggerDeps, params: ExtractValuesTriggerParams): Promise<ExtractValuesResult
|
|
103
|
-
/** Runs one extraction pass for the bound analysis, and gives the raw value map back. */
|
|
104
|
-
export type ExtractionRunner = (requests: readonly ExtractionRequest[]) => Promise<ExtractValuesResult
|
|
108
|
+
export declare function triggerExtractValues(deps: ExtractValuesTriggerDeps, params: ExtractValuesTriggerParams): Promise<Result<ExtractValuesResult, Suspension>>;
|
|
109
|
+
/** Runs one extraction pass for the bound analysis, and gives the raw value map back, or the suspension. */
|
|
110
|
+
export type ExtractionRunner = (requests: readonly ExtractionRequest[]) => Promise<Result<ExtractValuesResult, Suspension>>;
|
|
105
111
|
/**
|
|
106
112
|
* Bind the trigger to one analysis and one auth context. The result runs one pass with every request in it.
|
|
107
113
|
*/
|
|
@@ -119,6 +125,6 @@ export declare function extractionArtifactsFromResult(result: ExtractValuesResul
|
|
|
119
125
|
/**
|
|
120
126
|
* Make the extraction arm over a runner. One `extract` call makes one run with every request in it, and it
|
|
121
127
|
* gives the value map. A run fault rejects the promise, and the resolver turns the rejection into a failed
|
|
122
|
-
* reference.
|
|
128
|
+
* reference. A suspension is the `err`, and the resolver reports its reason on each reference.
|
|
123
129
|
*/
|
|
124
130
|
export declare function createExtractionArm(run: ExtractionRunner): ExtractionArm;
|
|
@@ -12,10 +12,15 @@
|
|
|
12
12
|
* standing machine exists.
|
|
13
13
|
*/
|
|
14
14
|
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
15
|
+
import { err, ok } from "neverthrow";
|
|
15
16
|
import { randomUUID } from "node:crypto";
|
|
17
|
+
import { forStep } from "../auth/types.js";
|
|
16
18
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
19
|
+
import { deliverNotice, passGate } from "../lib/hooks.js";
|
|
17
20
|
import { generateExecutionId } from "../sandbox/execution-id.js";
|
|
18
21
|
import { mintSandboxIdentity } from "../sandbox/identity.js";
|
|
22
|
+
import { keepSuspendingRefusal } from "../sandbox/sandbox-error.js";
|
|
23
|
+
import { suspensionOfRefusal, suspensionOfSpawnRefusal } from "../workflows/suspension.js";
|
|
19
24
|
import { EXTRACTION_INPUT_ENV, EXTRACTION_SCRIPT, ExtractValuesResultSchema } from "./extract-values-script.js";
|
|
20
25
|
/** The synthetic run id and step id of the extraction pass. Both are constants shared by every analysis. */
|
|
21
26
|
const EXTRACT_VALUES_RUN_LITERAL = "extract-values";
|
|
@@ -85,24 +90,28 @@ export function parseExtractionOutput(result) {
|
|
|
85
90
|
* The body, extracted so a test drives it without a registered workflow. It creates the ephemeral
|
|
86
91
|
* container, submits one exec, awaits the result durably, and gives the value map back. It revokes the run
|
|
87
92
|
* authorization on every terminal path, and it tears the container down on both paths.
|
|
93
|
+
*
|
|
94
|
+
* A chat turn awaits this workflow, thus a suspension is the `err` of the result, and the workflow does not
|
|
95
|
+
* cancel (workflow-suspension spec). The body does not mark the analysis: the caller reports the suspension.
|
|
88
96
|
*/
|
|
89
97
|
export async function runExtractValuesBody(input, deps) {
|
|
90
98
|
const logger = (deps.logger ?? createNoopLogger()).named("extract-values").with({ analysisId: input.analysisId });
|
|
91
99
|
const { analysisId, runSession, requests, ownsMandate = true } = input; // oss-core-managed-ok
|
|
92
100
|
const authorization = { runSession, ownsMandate }; // oss-core-managed-ok
|
|
101
|
+
const revoke = (reason) => deliverNotice(logger, "RunAuthorizer.revoke", deps.runAuthorizer.revoke(authorization, reason));
|
|
93
102
|
try {
|
|
94
103
|
const executionId = generateExecutionId(EXTRACT_VALUES_AGENT_ID);
|
|
95
104
|
const workflowId = DBOS.workflowID ?? `${EXTRACT_VALUES_RUN_LITERAL}:${executionId}`;
|
|
96
105
|
// The container mounts the analysis tree read-only. The extraction pass only reads, thus it needs
|
|
97
106
|
// no writable step mount.
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
const spawned = keepSuspendingRefusal(await deps.sandboxClient.createSandbox(forStep(runSession, EXTRACT_VALUES_STEP_LITERAL), { childWorkflowId: workflowId, resources: EXTRACTION_RESOURCES, readOnly: true }, mintSandboxIdentity(EXTRACT_VALUES_RUN_LITERAL)));
|
|
108
|
+
if (spawned.isErr()) {
|
|
109
|
+
const suspension = suspensionOfSpawnRefusal(spawned.error);
|
|
110
|
+
logger.warn("extraction suspended", { reason: suspension.reason });
|
|
111
|
+
await revoke("extract-values-suspended");
|
|
112
|
+
return err(suspension);
|
|
113
|
+
}
|
|
114
|
+
const sandbox = spawned.value;
|
|
106
115
|
try {
|
|
107
116
|
// A checkpointed clock, not `Date.now()`: the await gates on this absolute deadline, and a
|
|
108
117
|
// wall-clock deadline that grew on replay would shift which loop iteration crosses it.
|
|
@@ -110,8 +119,8 @@ export async function runExtractValuesBody(input, deps) {
|
|
|
110
119
|
await deps.sandboxClient.submitExec(sandbox, buildExtractionExec(analysisId, requests, executionId));
|
|
111
120
|
const result = await deps.sandboxClient.awaitExec(sandbox, executionId, noopEmit, deadlineAbs);
|
|
112
121
|
const map = parseExtractionOutput(result);
|
|
113
|
-
await
|
|
114
|
-
return map;
|
|
122
|
+
await revoke("extract-values-completed");
|
|
123
|
+
return ok(map);
|
|
115
124
|
}
|
|
116
125
|
finally {
|
|
117
126
|
try {
|
|
@@ -124,7 +133,7 @@ export async function runExtractValuesBody(input, deps) {
|
|
|
124
133
|
}
|
|
125
134
|
catch (err) {
|
|
126
135
|
logger.error("extraction failed", logger.errorFields(err));
|
|
127
|
-
await
|
|
136
|
+
await revoke("extract-values-failed");
|
|
128
137
|
throw err;
|
|
129
138
|
}
|
|
130
139
|
}
|
|
@@ -141,18 +150,25 @@ export function extractValuesWorkflowId(analysisId, nonce) {
|
|
|
141
150
|
}
|
|
142
151
|
/**
|
|
143
152
|
* The async edge. It authorizes through the `RunAuthorizer`, starts the workflow, and awaits the outcome.
|
|
144
|
-
* The body owns the revoke, thus the trigger holds no lifecycle. A workflow fault
|
|
145
|
-
* promise.
|
|
153
|
+
* The body owns the revoke, thus the trigger holds no lifecycle. A workflow fault and a refused
|
|
154
|
+
* authorization reject the returned promise. A suspension is the `err` of the result: of the workflow, or of
|
|
155
|
+
* an authorization that the host refused with the suspend flag.
|
|
146
156
|
*/
|
|
147
157
|
export async function triggerExtractValues(deps, params) {
|
|
148
158
|
const { auth, analysisId, requests } = params;
|
|
149
|
-
const
|
|
150
|
-
// oss-core-managed-ok
|
|
159
|
+
const authorized = await passGate("RunAuthorizer.authorize", deps.runAuthorizer.authorize({
|
|
151
160
|
auth,
|
|
152
161
|
scope: { kind: "analysis", analysisId },
|
|
153
162
|
provenance: { agentId: EXTRACT_VALUES_AGENT_ID, callPath: [EXTRACT_VALUES_AGENT_ID] },
|
|
154
163
|
frame: { runId: EXTRACT_VALUES_RUN_LITERAL, stepId: EXTRACT_VALUES_STEP_LITERAL },
|
|
155
|
-
});
|
|
164
|
+
}));
|
|
165
|
+
if (authorized.isErr()) {
|
|
166
|
+
const suspension = suspensionOfRefusal(authorized.error);
|
|
167
|
+
if (suspension !== undefined)
|
|
168
|
+
return err(suspension);
|
|
169
|
+
throw new Error(`the extraction was not authorized: ${authorized.error.reason}`);
|
|
170
|
+
}
|
|
171
|
+
const { runSession, ownsMandate } = authorized.value; // oss-core-managed-ok
|
|
156
172
|
const handle = (await DBOS.startWorkflow(deps.workflow, {
|
|
157
173
|
workflowID: extractValuesWorkflowId(analysisId, randomUUID()),
|
|
158
174
|
})({ analysisId, runSession, requests: [...requests], ownsMandate })); // oss-core-managed-ok
|
|
@@ -182,12 +198,12 @@ export function extractionArtifactsFromResult(result) {
|
|
|
182
198
|
/**
|
|
183
199
|
* Make the extraction arm over a runner. One `extract` call makes one run with every request in it, and it
|
|
184
200
|
* gives the value map. A run fault rejects the promise, and the resolver turns the rejection into a failed
|
|
185
|
-
* reference.
|
|
201
|
+
* reference. A suspension is the `err`, and the resolver reports its reason on each reference.
|
|
186
202
|
*/
|
|
187
203
|
export function createExtractionArm(run) {
|
|
188
204
|
return {
|
|
189
205
|
async extract(requests) {
|
|
190
|
-
return
|
|
206
|
+
return (await run(requests)).map(extractionArtifactsFromResult);
|
|
191
207
|
},
|
|
192
208
|
};
|
|
193
209
|
}
|
|
@@ -3,21 +3,23 @@
|
|
|
3
3
|
* hoc analyses. Both modes launch the ordinary executeAnalysis workflow.
|
|
4
4
|
*/
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
|
-
import { ok } from "neverthrow";
|
|
6
|
+
import { err, ok } from "neverthrow";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { SANDBOX_AGENT_META } from "../agents/sandbox/index.js";
|
|
9
9
|
import { DEFAULT_SANDBOX_MAX_STEPS } from "../config/resource-limits.js";
|
|
10
10
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
11
|
+
import { deliverNotice, passGate } from "../lib/hooks.js";
|
|
11
12
|
import { unwrapOrThrow } from "../lib/result.js";
|
|
12
13
|
import { buildRunCardData } from "../memory/card-builders.js";
|
|
13
14
|
import { formatQuery, parseQuery } from "../sandbox/package-identity.js";
|
|
14
15
|
import { AnalysisPlanSchema } from "../schemas/workflow-state.js";
|
|
15
16
|
import { validatePlan } from "../schemas/validate-plan.js";
|
|
16
|
-
import { RunDedupCollisionError, insertRun, loadPlan, queryActiveRun, reserveRunById, updateRunStatus, upsertPlan } from "../state/index.js";
|
|
17
|
+
import { RunDedupCollisionError, insertRun, loadPlan, queryActiveRun, reserveRunById, suspendAnalysis, updateRunStatus, upsertPlan } from "../state/index.js";
|
|
17
18
|
import { routeAdHocRequest } from "./ad-hoc-router.js";
|
|
18
19
|
import { adHocPlanId, adHocRunId } from "./analysis-invocation.js";
|
|
19
20
|
import { defineTool } from "./define-tool.js";
|
|
20
21
|
import { queryPackages, readInventorySections } from "./sandbox/list-available-packages.js";
|
|
22
|
+
import { callExtendAnalysisFarm } from "./sandbox/link-packages.js";
|
|
21
23
|
const planIdSchema = z.string().regex(/^pln-[a-f0-9]{8}$/, "planId must be a pln-<8hex> value");
|
|
22
24
|
const inputSchema = z
|
|
23
25
|
.object({
|
|
@@ -119,16 +121,13 @@ async function linkPlanPackages(extendAnalysisFarm, analysisId, plan) {
|
|
|
119
121
|
const queries = [...union.values()];
|
|
120
122
|
if (queries.length === 0)
|
|
121
123
|
return 0;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// A realization throw is an `unavailable` answer, not a driver error.
|
|
128
|
-
// The sibling resolver seam maps a throw the same way (farm.ts), and
|
|
129
|
-
// the planner can act on "the store cannot answer" — not on a stack.
|
|
130
|
-
throw new PlanPackagesMissingError([], [], cause instanceof Error ? cause.message : String(cause));
|
|
124
|
+
const linked = await callExtendAnalysisFarm(extendAnalysisFarm, analysisId, queries);
|
|
125
|
+
if (linked.isErr()) {
|
|
126
|
+
// A call that gave no answer is an `unavailable` answer, not a driver
|
|
127
|
+
// error: the planner can act on "the store cannot answer".
|
|
128
|
+
throw new PlanPackagesMissingError([], [], linked.error);
|
|
131
129
|
}
|
|
130
|
+
const outcomes = linked.value;
|
|
132
131
|
// An `unavailable` outcome preempts everything: the link pass could not
|
|
133
132
|
// answer at all (an unreadable graph, a locked farm), so a per-package
|
|
134
133
|
// absence list would be a fabrication. One reason covers the batch.
|
|
@@ -383,19 +382,25 @@ export function createExecuteAnalysisTool(deps) {
|
|
|
383
382
|
return ok({ runId: reservation.row.runId, status: "in_progress" });
|
|
384
383
|
}
|
|
385
384
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
385
|
+
const authorized = await passGate("RunAuthorizer.authorize", deps.runAuthorizer.authorize({
|
|
386
|
+
auth: ctx.session.auth,
|
|
387
|
+
scope: ctx.session.scope,
|
|
388
|
+
provenance: ctx.session.provenance,
|
|
389
|
+
frame: { runId },
|
|
390
|
+
}));
|
|
391
|
+
if (authorized.isErr()) {
|
|
392
|
+
// The refusal ends the run before a workflow exists, thus the
|
|
393
|
+
// reserved row must not stay `running`.
|
|
394
|
+
const { kind, reason } = authorized.error;
|
|
395
|
+
if (kind === "suspended") {
|
|
396
|
+
await updateRunStatus(deps.pool, runId, "canceled", reason).match(() => { }, () => { });
|
|
397
|
+
unwrapOrThrow(await suspendAnalysis(deps.pool, analysisId));
|
|
398
|
+
return err({ error: `The analysis is suspended: ${reason}`, retryable: false });
|
|
399
|
+
}
|
|
400
|
+
await updateRunStatus(deps.pool, runId, "failed", reason).match(() => { }, () => { });
|
|
401
|
+
return err({ error: `The run was not authorized: ${reason}`, retryable: false });
|
|
398
402
|
}
|
|
403
|
+
const authorization = authorized.value;
|
|
399
404
|
const wfInput = workflowInput(planId, plan, {
|
|
400
405
|
analysisId,
|
|
401
406
|
threadId,
|
|
@@ -408,7 +413,7 @@ export function createExecuteAnalysisTool(deps) {
|
|
|
408
413
|
await deps.runLauncher.launch(deps.executeAnalysisWorkflow, { workflowId: runId }, wfInput);
|
|
409
414
|
}
|
|
410
415
|
catch (error) {
|
|
411
|
-
await deps.runAuthorizer.revoke(authorization, "workflow-start-failed")
|
|
416
|
+
await deliverNotice(logger, "RunAuthorizer.revoke", deps.runAuthorizer.revoke(authorization, "workflow-start-failed"));
|
|
412
417
|
await updateRunStatus(deps.pool, runId, "failed", "workflow start failed").match(() => { }, () => { });
|
|
413
418
|
throw error;
|
|
414
419
|
}
|
|
@@ -33,7 +33,10 @@
|
|
|
33
33
|
* under the callback transport, and a report turn is not a body. Thus the tool takes an injected runner,
|
|
34
34
|
* and a registered workflow owns the container. The tool holds no sandbox client, and it imports no DBOS.
|
|
35
35
|
*/
|
|
36
|
+
import { type Result } from "neverthrow";
|
|
36
37
|
import { z } from "zod";
|
|
38
|
+
import type { RunSession } from "../../auth/types.js";
|
|
39
|
+
import type { Suspension } from "../../workflows/suspension.js";
|
|
37
40
|
import type { RunAuthorizer } from "../../execution/run-authorizer.js";
|
|
38
41
|
import { type Logger } from "../../lib/logger.js";
|
|
39
42
|
import type { ResourceSpec } from "../../config/resource-limits.js";
|
|
@@ -90,6 +93,10 @@ export type DeriveTableResult = {
|
|
|
90
93
|
} | {
|
|
91
94
|
outcome: "exec-failed";
|
|
92
95
|
detail: string;
|
|
96
|
+
} | {
|
|
97
|
+
outcome: "suspended";
|
|
98
|
+
reason: string;
|
|
99
|
+
detail: string;
|
|
93
100
|
} | {
|
|
94
101
|
outcome: "no-output";
|
|
95
102
|
detail: string;
|
|
@@ -172,6 +179,7 @@ export declare function describeExecFailure(result: ExecResult): string | undefi
|
|
|
172
179
|
*/
|
|
173
180
|
export interface DeriveTableExecInput {
|
|
174
181
|
readonly analysisId: string;
|
|
182
|
+
readonly runSession: RunSession;
|
|
175
183
|
readonly executionId: string;
|
|
176
184
|
readonly script: string;
|
|
177
185
|
readonly writableTail: string;
|
|
@@ -186,7 +194,7 @@ export interface DeriveTableExecInput {
|
|
|
186
194
|
* and the await is legal under each transport. A fault of the sandbox rejects the promise, and the tool
|
|
187
195
|
* turns that rejection into one short detail.
|
|
188
196
|
*/
|
|
189
|
-
export type DeriveTableRunner = (input: DeriveTableExecInput) => Promise<ExecResult
|
|
197
|
+
export type DeriveTableRunner = (input: DeriveTableExecInput) => Promise<Result<ExecResult, Suspension>>;
|
|
190
198
|
/**
|
|
191
199
|
* Make the derivation tool over the session-state gateway, the derivation ledger, and the sandbox rails.
|
|
192
200
|
*
|
|
@@ -38,6 +38,7 @@ import { unlink } from "node:fs/promises";
|
|
|
38
38
|
import { join } from "node:path";
|
|
39
39
|
import { z } from "zod";
|
|
40
40
|
import { createNoopLogger } from "../../lib/console-logger.js";
|
|
41
|
+
import { deliverNotice, passGate } from "../../lib/hooks.js";
|
|
41
42
|
import { classifyWithinRoot, computeSha256, computeSha256File } from "../../lib/fs-helpers.js";
|
|
42
43
|
import { defaultErrorFields } from "../../lib/logger.js";
|
|
43
44
|
import { snapshotEntry } from "../../report-model/reference-resolver.js";
|
|
@@ -223,19 +224,20 @@ export function createDeriveTableTool(deps) {
|
|
|
223
224
|
logger.warn("the workspace root did not resolve", { threadId, analysisId, ...defaultErrorFields(cause) });
|
|
224
225
|
return ok({ outcome: "unavailable", detail: "the workspace root did not resolve, thus the derived table has no place to land" });
|
|
225
226
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
return ok({ outcome: "unavailable", detail:
|
|
227
|
+
const authorized = await passGate("RunAuthorizer.authorize", runAuthorizer.authorize({
|
|
228
|
+
auth: ctx.session.auth,
|
|
229
|
+
scope: { kind: "analysis", analysisId },
|
|
230
|
+
provenance: { agentId: DERIVE_AGENT_ID, callPath: [DERIVE_AGENT_ID] },
|
|
231
|
+
frame: { runId: DERIVE_RUN_LITERAL, stepId: DERIVE_STEP_LITERAL },
|
|
232
|
+
}));
|
|
233
|
+
if (authorized.isErr()) {
|
|
234
|
+
const { kind, reason } = authorized.error;
|
|
235
|
+
logger.error("the derivation was not authorized", { threadId, analysisId, reason, suspend: kind === "suspended" });
|
|
236
|
+
if (kind === "suspended")
|
|
237
|
+
return ok({ outcome: "suspended", reason, detail: `the analysis is suspended (${reason}), thus the derivation did not run` });
|
|
238
|
+
return ok({ outcome: "unavailable", detail: `the derivation was not authorized: ${reason}` });
|
|
238
239
|
}
|
|
240
|
+
const authorization = authorized.value;
|
|
239
241
|
// The work sits inside the `try`, and the revoke sits in the `finally`. Thus the authorization
|
|
240
242
|
// revokes on every terminal path, the thrown one included: a path builder refuses a hostile
|
|
241
243
|
// stored path with a throw, and that throw must not leave an authorization standing.
|
|
@@ -247,6 +249,7 @@ export function createDeriveTableTool(deps) {
|
|
|
247
249
|
root,
|
|
248
250
|
threadId,
|
|
249
251
|
analysisId,
|
|
252
|
+
runSession: authorization.runSession,
|
|
250
253
|
script: input.script,
|
|
251
254
|
sources,
|
|
252
255
|
writableTail,
|
|
@@ -270,14 +273,9 @@ export function createDeriveTableTool(deps) {
|
|
|
270
273
|
return ok(result);
|
|
271
274
|
}
|
|
272
275
|
finally {
|
|
273
|
-
//
|
|
274
|
-
// result means that the work threw, and a throw is a failed derivation.
|
|
275
|
-
|
|
276
|
-
await runAuthorizer.revoke(authorization, result?.outcome === "derived" ? "derive-table-completed" : "derive-table-failed");
|
|
277
|
-
}
|
|
278
|
-
catch (cause) {
|
|
279
|
-
logger.warn("the derivation authorization did not revoke", { threadId, analysisId, ...defaultErrorFields(cause) });
|
|
280
|
-
}
|
|
276
|
+
// The revoke is a notice: its failure changes no outcome of the call, thus it reaches the log
|
|
277
|
+
// alone. An absent result means that the work threw, and a throw is a failed derivation.
|
|
278
|
+
await deliverNotice(logger.with({ threadId, analysisId }), "RunAuthorizer.revoke", runAuthorizer.revoke(authorization, result?.outcome === "derived" ? "derive-table-completed" : "derive-table-failed"));
|
|
281
279
|
}
|
|
282
280
|
},
|
|
283
281
|
});
|
|
@@ -318,6 +316,7 @@ async function derive(args) {
|
|
|
318
316
|
// thus that refusal stays a throw and it never reads as a fault of the container.
|
|
319
317
|
const execInput = {
|
|
320
318
|
analysisId: args.analysisId,
|
|
319
|
+
runSession: args.runSession,
|
|
321
320
|
executionId,
|
|
322
321
|
script: args.script,
|
|
323
322
|
writableTail: args.writableTail,
|
|
@@ -325,14 +324,18 @@ async function derive(args) {
|
|
|
325
324
|
inputs: args.sources.map((source) => ({ path: toSandboxPath(args.root, args.analysisId, join(args.root, source.path)), hash: source.hash })),
|
|
326
325
|
output: toSandboxPath(args.root, args.analysisId, absolute),
|
|
327
326
|
};
|
|
328
|
-
let
|
|
327
|
+
let ran;
|
|
329
328
|
try {
|
|
330
|
-
|
|
329
|
+
ran = await args.runDerivation(execInput);
|
|
331
330
|
}
|
|
332
331
|
catch (cause) {
|
|
333
332
|
args.logger.error("the derivation exec did not complete", { threadId: args.threadId, ...defaultErrorFields(cause) });
|
|
334
333
|
return { outcome: "exec-failed", detail: "the derivation exec did not complete" };
|
|
335
334
|
}
|
|
335
|
+
if (ran.isErr()) {
|
|
336
|
+
return { outcome: "suspended", reason: ran.error.reason, detail: `the analysis is suspended (${ran.error.reason}), thus the derivation did not run` };
|
|
337
|
+
}
|
|
338
|
+
const executed = ran.value;
|
|
336
339
|
const failure = describeExecFailure(executed);
|
|
337
340
|
if (failure !== undefined) {
|
|
338
341
|
return { outcome: "exec-failed", detail: failure };
|
|
@@ -37,16 +37,19 @@
|
|
|
37
37
|
* one and the look cannot count. The tool then gives a missed-stamp outcome that directs a new preview,
|
|
38
38
|
* because a repeated look never stamps a marker that no preview wrote.
|
|
39
39
|
*
|
|
40
|
-
* The eyes seam, the chrome navigation, and the workspace-root seam each speak the throw protocol. The
|
|
41
|
-
* guards each of them, thus a fault of a look becomes a typed outcome and
|
|
40
|
+
* The eyes seam, the chrome navigation, and the workspace-root seam each speak the throw protocol. The URL
|
|
41
|
+
* seam gives a `Result`. The tool guards each of them, thus a fault of a look becomes a typed outcome and
|
|
42
|
+
* the loop never sees a throw.
|
|
42
43
|
*
|
|
43
44
|
* A hang is not a throw, and a guard alone never ends one. Thus the acquire and the release each carry a
|
|
44
45
|
* deadline. A realization that hangs while it starts a browser would otherwise hold the whole agent turn,
|
|
45
46
|
* and no outcome would ever arrive.
|
|
46
47
|
*/
|
|
48
|
+
import { type ResultAsync } from "neverthrow";
|
|
47
49
|
import { z } from "zod";
|
|
48
50
|
import type { AuthContext } from "../../auth/types.js";
|
|
49
51
|
import { type ChromeConfig } from "../../lib/chrome.js";
|
|
52
|
+
import type { GateFailure } from "../../lib/hooks.js";
|
|
50
53
|
import { type AcquireEyes } from "../../lib/eyes.js";
|
|
51
54
|
import { type Logger } from "../../lib/logger.js";
|
|
52
55
|
import { type CaptureCoverage, type CapturePage, type FailedRequest, type PageCapture } from "../../lib/page-capture.js";
|
|
@@ -65,7 +68,7 @@ export type ResolvePageUrl = (args: {
|
|
|
65
68
|
analysisId: string;
|
|
66
69
|
threadId: string;
|
|
67
70
|
auth: AuthContext;
|
|
68
|
-
}) =>
|
|
71
|
+
}) => ResultAsync<string, GateFailure>;
|
|
69
72
|
/** The empty input. The tool examines the current page of the thread, thus it needs no field. */
|
|
70
73
|
declare const examinePageInput: z.ZodObject<{}, z.core.$strip>;
|
|
71
74
|
export type ExaminePageInput = z.infer<typeof examinePageInput>;
|
|
@@ -37,8 +37,9 @@
|
|
|
37
37
|
* one and the look cannot count. The tool then gives a missed-stamp outcome that directs a new preview,
|
|
38
38
|
* because a repeated look never stamps a marker that no preview wrote.
|
|
39
39
|
*
|
|
40
|
-
* The eyes seam, the chrome navigation, and the workspace-root seam each speak the throw protocol. The
|
|
41
|
-
* guards each of them, thus a fault of a look becomes a typed outcome and
|
|
40
|
+
* The eyes seam, the chrome navigation, and the workspace-root seam each speak the throw protocol. The URL
|
|
41
|
+
* seam gives a `Result`. The tool guards each of them, thus a fault of a look becomes a typed outcome and
|
|
42
|
+
* the loop never sees a throw.
|
|
42
43
|
*
|
|
43
44
|
* A hang is not a throw, and a guard alone never ends one. Thus the acquire and the release each carry a
|
|
44
45
|
* deadline. A realization that hangs while it starts a browser would otherwise hold the whole agent turn,
|
|
@@ -273,14 +274,21 @@ export function createExaminePageTool(deps) {
|
|
|
273
274
|
logger.warn("the session page could not be read", { threadId, analysisId, ...defaultErrorFields(cause) });
|
|
274
275
|
return ok({ outcome: "capture-failed", detail: "the session page could not be read" });
|
|
275
276
|
}
|
|
276
|
-
//
|
|
277
|
-
//
|
|
277
|
+
// An `err` of the URL seam and a rejected realization each become a typed outcome, and the look
|
|
278
|
+
// never starts.
|
|
278
279
|
let url;
|
|
279
280
|
try {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
if (deps.resolvePageUrl === undefined) {
|
|
282
|
+
url = pathToFileURL(pagePath).href;
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
const resolved = await deps.resolvePageUrl({ pagePath, analysisId, threadId, auth: ctx.session.auth });
|
|
286
|
+
if (resolved.isErr()) {
|
|
287
|
+
logger.warn("the page URL did not resolve", { threadId, analysisId, reason: resolved.error.reason });
|
|
288
|
+
return ok({ outcome: "capture-failed", detail: "the page URL did not resolve" });
|
|
289
|
+
}
|
|
290
|
+
url = resolved.value;
|
|
291
|
+
}
|
|
284
292
|
}
|
|
285
293
|
catch (cause) {
|
|
286
294
|
logger.warn("the page URL did not resolve", { threadId, analysisId, ...defaultErrorFields(cause) });
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { createPreviewReportTool, type PreviewReportInput, type PreviewReportResult, type PreviewReportToolDeps, type ResolvePageAsset, type SessionPageAccess, } from "./preview-report.js";
|
|
9
9
|
export { createExaminePageTool, type CaptureCoverage, type CapturePage, type ExaminedTile, type ExaminePageInput, type ExaminePageResult, type ExaminePageToolDeps, type FailedRequest, type PageCapture, type ResolvePageUrl, } from "./examine-page.js";
|
|
10
|
-
export { describeSessionPageMintFailure, UnavailableSessionPagePublisher, type MakeSessionPagePublisher, type
|
|
10
|
+
export { describeSessionPageMintFailure, UnavailableSessionPagePublisher, type MakeSessionPagePublisher, type SessionPageGrant, type SessionPageMintFailure, type SessionPagePublisher, } from "./session-page-publisher.js";
|
|
11
11
|
export { createRecordVersionTool, type RecordVersionInput, type RecordVersionResult, type RecordVersionToolDeps } from "./record-version.js";
|
|
12
12
|
export { createDeriveTableTool, type DeriveTableInput, type DeriveTableResult, type DeriveTableToolDeps } from "./derive-table.js";
|
|
13
13
|
export { createListPinnedArtifactsTool, type ListPinnedArtifactsInput, type ListPinnedArtifactsResult, type ListPinnedArtifactsToolDeps, type PinnedArtifact, type PinnedCitation, } from "./list-artifacts.js";
|