@inflexa-ai/harness 0.12.0 → 0.14.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/dist/agents/conversation-agent.d.ts +9 -15
- package/dist/agents/conversation-agent.js +32 -31
- package/dist/agents/sandbox/cheminformatics-agent.js +1 -1
- package/dist/agents/sandbox/chromatin-agent.js +1 -1
- package/dist/agents/sandbox/dna-methylation-agent.js +1 -1
- package/dist/agents/sandbox/drug-repurposing-agent.js +5 -10
- package/dist/agents/sandbox/enrichment-agent.js +1 -1
- package/dist/agents/sandbox/genomic-variant-agent.js +1 -11
- package/dist/agents/sandbox/immune-profiling-agent.js +1 -1
- package/dist/agents/sandbox/index.js +0 -3
- package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -1
- package/dist/agents/sandbox/network-agent.js +1 -1
- package/dist/agents/sandbox/pkpd-clinical-response-agent.js +3 -6
- package/dist/agents/sandbox/scientific-executor.js +1 -1
- package/dist/agents/sandbox/shared.d.ts +2 -2
- package/dist/agents/sandbox/shared.js +8 -14
- package/dist/agents/sandbox/translational-safety-agent.js +4 -7
- package/dist/agents/sandbox/types.d.ts +5 -5
- package/dist/agents/sandbox/types.js +4 -4
- package/dist/app/chat-turn.js +4 -1
- package/dist/app/message-assembly.d.ts +5 -2
- package/dist/app/message-assembly.js +7 -2
- package/dist/app/run-activity.d.ts +13 -0
- package/dist/app/run-activity.js +51 -0
- package/dist/config/resource-limits.d.ts +0 -7
- package/dist/config/resource-limits.js +0 -1
- package/dist/contracts/target-dossier.d.ts +10 -10
- package/dist/execution/dbos-run-launcher.js +1 -26
- package/dist/execution/report-runner.js +1 -1
- package/dist/execution/run-authorizer.d.ts +1 -1
- package/dist/execution/run-authorizer.js +1 -1
- package/dist/execution/run-event-parts.d.ts +44 -0
- package/dist/execution/run-event-parts.js +0 -0
- package/dist/execution/run-event-stream.d.ts +91 -0
- package/dist/execution/run-event-stream.js +212 -0
- package/dist/execution/run-launcher.d.ts +2 -18
- package/dist/execution/run-launcher.js +2 -4
- package/dist/execution/run-synthesis.js +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +23 -6
- package/dist/input-sanitization.d.ts +14 -4
- package/dist/input-sanitization.js +27 -4
- package/dist/lib/storage.js +4 -1
- package/dist/loop/budget-exceeded.d.ts +18 -2
- package/dist/loop/budget-exceeded.js +49 -2
- package/dist/loop/run-agent.d.ts +22 -1
- package/dist/loop/run-agent.js +51 -5
- package/dist/loop/run-to-terminal.d.ts +0 -2
- package/dist/loop/run-to-terminal.js +8 -1
- package/dist/memory/ai-sdk-message-storage.d.ts +37 -4
- package/dist/memory/ai-sdk-message-storage.js +45 -4
- package/dist/memory/content-to-cortex.js +19 -3
- package/dist/memory/message-backfill.js +1 -1
- package/dist/memory/reconstruct-cards.d.ts +1 -1
- package/dist/memory/reconstruct-cards.js +7 -5
- package/dist/memory/thread-history.js +72 -8
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +41 -15
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +16 -14
- package/dist/prompts/planner.d.ts +3 -0
- package/dist/prompts/planner.js +16 -21
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +31 -22
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +9 -10
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +8 -7
- package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.js +20 -14
- package/dist/prompts/sandbox-standards.d.ts +4 -4
- package/dist/prompts/sandbox-standards.js +5 -5
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +7 -7
- package/dist/providers/errors.d.ts +7 -0
- package/dist/providers/errors.js +88 -3
- package/dist/runtime/assemble.d.ts +5 -10
- package/dist/runtime/assemble.js +0 -4
- package/dist/runtime/boot.d.ts +2 -2
- package/dist/runtime/boot.js +1 -1
- package/dist/runtime/dbos.d.ts +4 -5
- package/dist/runtime/dbos.js +6 -7
- package/dist/runtime/pools.d.ts +15 -1
- package/dist/runtime/pools.js +15 -1
- package/dist/sandbox/mount-plan.d.ts +1 -1
- package/dist/sandbox/sandbox-error.d.ts +1 -1
- package/dist/sandbox/sandbox-error.js +1 -1
- package/dist/sandbox/sandbox-step-translate.d.ts +15 -2
- package/dist/sandbox/sandbox-step-translate.js +17 -2
- package/dist/sandbox/types.d.ts +1 -1
- package/dist/schemas/validate-plan.d.ts +1 -1
- package/dist/schemas/workflow-state.d.ts +2 -2
- package/dist/schemas/workflow-state.js +2 -2
- package/dist/state/data-profile.d.ts +53 -1
- package/dist/state/data-profile.js +66 -6
- package/dist/state/index.d.ts +6 -6
- package/dist/state/index.js +4 -4
- package/dist/state/init.js +37 -2
- package/dist/state/plans.js +1 -1
- package/dist/state/runs.d.ts +49 -0
- package/dist/state/runs.js +150 -0
- package/dist/tasks/data-profile-activity.d.ts +87 -0
- package/dist/tasks/data-profile-activity.js +56 -0
- package/dist/tasks/data-profile.js +66 -4
- package/dist/tools/__fixtures__/tool-context.js +1 -0
- package/dist/tools/ad-hoc-router.d.ts +31 -0
- package/dist/tools/ad-hoc-router.js +132 -0
- package/dist/tools/analysis-invocation.d.ts +4 -0
- package/dist/tools/analysis-invocation.js +17 -0
- package/dist/tools/bio/chembl.d.ts +1 -1
- package/dist/tools/bio/chembl.js +51 -54
- package/dist/tools/bio/comptox.js +35 -33
- package/dist/tools/bio/drug-gene-interactions.d.ts +76 -0
- package/dist/tools/bio/drug-gene-interactions.js +175 -0
- package/dist/tools/bio/gene-disease-evidence.d.ts +61 -0
- package/dist/tools/bio/gene-disease-evidence.js +187 -0
- package/dist/tools/bio/gene-preclinical-profile.d.ts +58 -0
- package/dist/tools/bio/gene-preclinical-profile.js +125 -0
- package/dist/tools/bio/index.d.ts +23 -16
- package/dist/tools/bio/index.js +29 -22
- package/dist/tools/bio/keys.d.ts +16 -9
- package/dist/tools/bio/keys.js +22 -13
- package/dist/tools/bio/lookup-annotation.d.ts +48 -0
- package/dist/tools/bio/lookup-annotation.js +173 -0
- package/dist/tools/bio/opentargets.d.ts +7 -11
- package/dist/tools/bio/opentargets.js +24 -35
- package/dist/tools/bio/pubchem.js +6 -4
- package/dist/tools/bio/pubmed.d.ts +15 -7
- package/dist/tools/bio/pubmed.js +79 -20
- package/dist/tools/bio/search-clinical-trials.d.ts +20 -1
- package/dist/tools/bio/search-clinical-trials.js +26 -5
- package/dist/tools/bio/search-faers.js +9 -3
- package/dist/tools/bio/search-gene.d.ts +0 -1
- package/dist/tools/bio/search-gene.js +4 -5
- package/dist/tools/bio/search-geo-datasets.js +10 -4
- package/dist/tools/bio/search-interactions.d.ts +8 -4
- package/dist/tools/bio/search-interactions.js +28 -12
- package/dist/tools/bio/target-safety.d.ts +59 -0
- package/dist/tools/bio/target-safety.js +191 -0
- package/dist/tools/define-tool.d.ts +6 -2
- package/dist/tools/define-tool.js +1 -1
- package/dist/tools/execute-analysis.d.ts +44 -0
- package/dist/tools/execute-analysis.js +252 -0
- package/dist/tools/iterate-report.js +7 -6
- package/dist/tools/lib/dgidb-client.d.ts +49 -0
- package/dist/tools/lib/dgidb-client.js +168 -0
- package/dist/tools/lib/disgenet-client.d.ts +56 -0
- package/dist/tools/lib/disgenet-client.js +59 -0
- package/dist/tools/lib/drugbank-client.d.ts +83 -0
- package/dist/tools/lib/drugbank-client.js +95 -0
- package/dist/tools/lib/ensembl-client.d.ts +4 -1
- package/dist/tools/lib/ensembl-client.js +5 -3
- package/dist/tools/lib/gwas-catalog-client.d.ts +60 -0
- package/dist/tools/lib/gwas-catalog-client.js +136 -0
- package/dist/tools/lib/pharmgkb-client.d.ts +22 -0
- package/dist/tools/lib/pharmgkb-client.js +32 -0
- package/dist/tools/lib/pubmed-client.d.ts +57 -4
- package/dist/tools/lib/pubmed-client.js +57 -3
- package/dist/tools/lib/string-client.d.ts +25 -4
- package/dist/tools/lib/string-client.js +22 -5
- package/dist/tools/research/generate-plan.d.ts +16 -9
- package/dist/tools/research/generate-plan.js +116 -70
- package/dist/tools/research/inspect-data-profile.d.ts +31 -6
- package/dist/tools/research/inspect-data-profile.js +23 -7
- package/dist/tools/research/inspect-run.d.ts +33 -15
- package/dist/tools/research/inspect-run.js +155 -66
- package/dist/tools/research/literature-reviewer.js +7 -11
- package/dist/workflows/execute-analysis.d.ts +68 -5
- package/dist/workflows/execute-analysis.js +76 -7
- package/dist/workflows/sandbox-step.js +1 -11
- package/dist/workflows/target-assessment/decisions/index.d.ts +1 -1
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +1 -1
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +2 -2
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +1 -1
- package/package.json +1 -1
- package/dist/agents/sandbox/ephemeral-executor.d.ts +0 -9
- package/dist/agents/sandbox/ephemeral-executor.js +0 -20
- package/dist/execution/ephemeral-runner.d.ts +0 -98
- package/dist/execution/ephemeral-runner.js +0 -189
- package/dist/prompts/sandbox/ephemeral-executor.d.ts +0 -1
- package/dist/prompts/sandbox/ephemeral-executor.js +0 -66
- package/dist/tools/bio/check-safety-panel.d.ts +0 -35
- package/dist/tools/bio/check-safety-panel.js +0 -76
- package/dist/tools/bio/get-impc-ko-profile.d.ts +0 -9
- package/dist/tools/bio/get-impc-ko-profile.js +0 -23
- package/dist/tools/bio/lookup-go-term.d.ts +0 -31
- package/dist/tools/bio/lookup-go-term.js +0 -116
- package/dist/tools/bio/search-bgee-expression.d.ts +0 -10
- package/dist/tools/bio/search-bgee-expression.js +0 -30
- package/dist/tools/bio/search-clinvar.d.ts +0 -13
- package/dist/tools/bio/search-clinvar.js +0 -28
- package/dist/tools/bio/search-dgidb.d.ts +0 -53
- package/dist/tools/bio/search-dgidb.js +0 -213
- package/dist/tools/bio/search-disgenet.d.ts +0 -30
- package/dist/tools/bio/search-disgenet.js +0 -84
- package/dist/tools/bio/search-drugbank.d.ts +0 -38
- package/dist/tools/bio/search-drugbank.js +0 -109
- package/dist/tools/bio/search-gwas-catalog.d.ts +0 -33
- package/dist/tools/bio/search-gwas-catalog.js +0 -172
- package/dist/tools/bio/search-pathway.d.ts +0 -12
- package/dist/tools/bio/search-pathway.js +0 -32
- package/dist/tools/bio/search-pharmgkb.d.ts +0 -17
- package/dist/tools/bio/search-pharmgkb.js +0 -52
- package/dist/tools/execute-plan.d.ts +0 -64
- package/dist/tools/execute-plan.js +0 -211
- package/dist/tools/run-ephemeral.d.ts +0 -33
- package/dist/tools/run-ephemeral.js +0 -65
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* executePlan — launch the DBOS `executeAnalysis` parent workflow for an
|
|
3
|
-
* approved plan.
|
|
4
|
-
*
|
|
5
|
-
* Results are pull-only: the tool does NOT register a `.then(saveRunResult)`
|
|
6
|
-
* or any completion callback that writes to the conversation thread. The
|
|
7
|
-
* conversation agent retrieves run results via `inspectRun` on a later turn.
|
|
8
|
-
*
|
|
9
|
-
* Authorization contract: the tool runs in the chat HTTP route, so its session
|
|
10
|
-
* carries the live auth. It authorizes through the injected `RunAuthorizer`
|
|
11
|
-
* seam and never reads a credential. The flow is dedup → reserve → authorize
|
|
12
|
-
* → startWorkflow:
|
|
13
|
-
*
|
|
14
|
-
* 1. Dedup pre-check via `queryActiveRun`. On hit, return the existing
|
|
15
|
-
* `runId` with no authorization and no `startWorkflow`.
|
|
16
|
-
* 2. Reserve the slot: `insertRun` the `cortex_runs` row (`runId =
|
|
17
|
-
* randomUUID()`, the bare UUID that IS the DBOS workflowID) BEFORE
|
|
18
|
-
* authorizing. The partial-unique index is the race backstop; the loser
|
|
19
|
-
* returns the winner's `runId` without authorizing — nothing to revoke.
|
|
20
|
-
* 3. `runAuthorizer.authorize({ ..., frame: { runId } })` — authorizes the
|
|
21
|
-
* run; the authorizer's persisted handle now lands because the row
|
|
22
|
-
* exists. On failure, mark the reserved row `failed` (releasing the dedup
|
|
23
|
-
* slot for a retry) and rethrow.
|
|
24
|
-
* 4. `runLauncher.launch(executeAnalysis, { workflowId: runId }, ...)`,
|
|
25
|
-
* passing the `RunSession` in the workflow input. On failure, revoke + mark
|
|
26
|
-
* failed.
|
|
27
|
-
*/
|
|
28
|
-
import { randomUUID } from "node:crypto";
|
|
29
|
-
import { ok } from "neverthrow";
|
|
30
|
-
import { z } from "zod";
|
|
31
|
-
import { buildRunCardData } from "../memory/card-builders.js";
|
|
32
|
-
import { unwrapOrThrow } from "../lib/result.js";
|
|
33
|
-
import { validatePlan } from "../schemas/validate-plan.js";
|
|
34
|
-
import { AnalysisPlanSchema } from "../schemas/workflow-state.js";
|
|
35
|
-
import { RunDedupCollisionError, insertRun, loadPlan, queryActiveRun, updateRunStatus } from "../state/index.js";
|
|
36
|
-
import { defineTool } from "./define-tool.js";
|
|
37
|
-
const planIdSchema = z.string().regex(/^pln-[a-f0-9]{8}$/, "planId must be a pln-<8hex> value");
|
|
38
|
-
const inputSchema = z.object({
|
|
39
|
-
planId: planIdSchema,
|
|
40
|
-
});
|
|
41
|
-
export class PlanNotFoundError extends Error {
|
|
42
|
-
constructor(planId) {
|
|
43
|
-
super(`Plan ${planId} not found for this analysis`);
|
|
44
|
-
this.name = "PlanNotFoundError";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export class PlanMalformedError extends Error {
|
|
48
|
-
constructor(planId) {
|
|
49
|
-
super(`Plan ${planId} is malformed`);
|
|
50
|
-
this.name = "PlanMalformedError";
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
export class PlanValidationError extends Error {
|
|
54
|
-
errors;
|
|
55
|
-
constructor(planId, errors) {
|
|
56
|
-
super(`Plan ${planId} failed validation: ${errors.length} error(s)`);
|
|
57
|
-
this.errors = errors;
|
|
58
|
-
this.name = "PlanValidationError";
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
function isDedupCollision(err) {
|
|
62
|
-
return err instanceof RunDedupCollisionError || (err instanceof Error && err.name === "RunDedupCollisionError");
|
|
63
|
-
}
|
|
64
|
-
export function createExecutePlanTool(deps) {
|
|
65
|
-
const { pool, executeAnalysisWorkflow, runAuthorizer, runLauncher, resourcePolicy } = deps;
|
|
66
|
-
return defineTool({
|
|
67
|
-
id: "execute_plan",
|
|
68
|
-
description: "Execute an approved analysis plan by its planId. " +
|
|
69
|
-
"Pass the planId returned from generatePlan — the tool resolves the plan " +
|
|
70
|
-
"server-side, validates the DAG, and starts the executeAnalysis workflow " +
|
|
71
|
-
"asynchronously. Returns the runId on success. " +
|
|
72
|
-
"The user sees a run card in chat (also tracked in the Runs panel); " +
|
|
73
|
-
"run results become available for inspection on a later turn. " +
|
|
74
|
-
"Do not instruct the user to invoke any tool.",
|
|
75
|
-
inputSchema,
|
|
76
|
-
execute: async (input, ctx) => {
|
|
77
|
-
const { planId } = input;
|
|
78
|
-
// Mirror show_plan: emit a live display card so chat renders a run card
|
|
79
|
-
// rather than a generic "used 1 tool" chip. Null (plan/run unresolvable)
|
|
80
|
-
// simply skips the card — the run still starts.
|
|
81
|
-
const emitRunCard = async (analysisId, runId) => {
|
|
82
|
-
const card = await buildRunCardData(pool, {
|
|
83
|
-
planId,
|
|
84
|
-
analysisId,
|
|
85
|
-
runId,
|
|
86
|
-
}).unwrapOr(null);
|
|
87
|
-
if (card) {
|
|
88
|
-
await ctx.emit({
|
|
89
|
-
type: "data-run-card",
|
|
90
|
-
source: ctx.session.provenance,
|
|
91
|
-
data: card,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
const { session } = ctx;
|
|
96
|
-
if (session.scope.kind !== "analysis") {
|
|
97
|
-
throw new Error("executePlan can only be invoked on an analysis-scoped session");
|
|
98
|
-
}
|
|
99
|
-
if (!session.auth) {
|
|
100
|
-
throw new Error("executePlan: session is missing its auth capability");
|
|
101
|
-
}
|
|
102
|
-
const analysisId = session.scope.analysisId;
|
|
103
|
-
const threadId = session.scope.threadId ?? null;
|
|
104
|
-
const raw = unwrapOrThrow(await loadPlan(pool, planId, { analysisId }));
|
|
105
|
-
if (!raw)
|
|
106
|
-
throw new PlanNotFoundError(planId);
|
|
107
|
-
const parsed = AnalysisPlanSchema.safeParse(raw);
|
|
108
|
-
if (!parsed.success)
|
|
109
|
-
throw new PlanMalformedError(planId);
|
|
110
|
-
const plan = parsed.data;
|
|
111
|
-
const result = validatePlan(plan);
|
|
112
|
-
if (!result.valid) {
|
|
113
|
-
throw new PlanValidationError(planId, result.errors);
|
|
114
|
-
}
|
|
115
|
-
// (1) Dedup pre-check — common case is the user re-clicked Execute on
|
|
116
|
-
// an in-flight plan. A hit avoids both the authorization and the DBOS
|
|
117
|
-
// startWorkflow.
|
|
118
|
-
const existingPre = unwrapOrThrow(await queryActiveRun(pool, analysisId, planId));
|
|
119
|
-
if (existingPre) {
|
|
120
|
-
await emitRunCard(analysisId, existingPre.runId);
|
|
121
|
-
return ok({ runId: existingPre.runId });
|
|
122
|
-
}
|
|
123
|
-
// (2) Reserve the dedup slot by inserting the run row BEFORE authorizing.
|
|
124
|
-
// The partial-unique index is the race backstop for two callers that both
|
|
125
|
-
// passed the pre-check; the loser returns the winner's runId without
|
|
126
|
-
// having authorized — there is nothing to revoke. The authorization handle is left
|
|
127
|
-
// null here and populated by the authorizer, whose UPDATE lands
|
|
128
|
-
// because the row now exists.
|
|
129
|
-
const runId = randomUUID();
|
|
130
|
-
try {
|
|
131
|
-
// On the dedup collision `insertRun` throws `RunDedupCollisionError`
|
|
132
|
-
// (a control-flow signal that rides out of the ResultAsync as a
|
|
133
|
-
// rejection) — `unwrapOrThrow` never sees it; the catch below does.
|
|
134
|
-
unwrapOrThrow(await insertRun(pool, {
|
|
135
|
-
runId,
|
|
136
|
-
analysisId,
|
|
137
|
-
threadId,
|
|
138
|
-
workflowName: "executeAnalysis",
|
|
139
|
-
planId,
|
|
140
|
-
}));
|
|
141
|
-
}
|
|
142
|
-
catch (err) {
|
|
143
|
-
if (isDedupCollision(err)) {
|
|
144
|
-
const existing = unwrapOrThrow(await queryActiveRun(pool, analysisId, planId));
|
|
145
|
-
if (existing) {
|
|
146
|
-
await emitRunCard(analysisId, existing.runId);
|
|
147
|
-
return ok({ runId: existing.runId });
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
throw err;
|
|
151
|
-
}
|
|
152
|
-
// (3) Authorize the run. The row exists, so the authorizer's persisted handle
|
|
153
|
-
// persists. On failure, mark the reserved row failed — releasing the
|
|
154
|
-
// partial-unique slot so a retry can re-run — and rethrow.
|
|
155
|
-
let authorization;
|
|
156
|
-
try {
|
|
157
|
-
authorization = await runAuthorizer.authorize({
|
|
158
|
-
auth: session.auth,
|
|
159
|
-
scope: session.scope,
|
|
160
|
-
provenance: session.provenance,
|
|
161
|
-
frame: { runId },
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
catch (err) {
|
|
165
|
-
await updateRunStatus(pool, runId, "failed", "run authorization failed").match(() => { }, () => { });
|
|
166
|
-
throw err;
|
|
167
|
-
}
|
|
168
|
-
const { runSession } = authorization;
|
|
169
|
-
const planSummary = plan.title?.trim() || plan.analytical_narrative.trim().slice(0, 280);
|
|
170
|
-
const workflowInput = {
|
|
171
|
-
analysisId,
|
|
172
|
-
planId,
|
|
173
|
-
planSummary,
|
|
174
|
-
threadId,
|
|
175
|
-
steps: plan.steps.map((s) => ({
|
|
176
|
-
id: s.id,
|
|
177
|
-
depends_on: s.depends_on ?? [],
|
|
178
|
-
})),
|
|
179
|
-
// The step DATA, not a rendered prompt: each step's seed is composed
|
|
180
|
-
// by the scheduler at dispatch, when its dependencies' results exist.
|
|
181
|
-
// A prompt frozen here — before the first step has run — could never
|
|
182
|
-
// mention them.
|
|
183
|
-
planStepById: Object.fromEntries(plan.steps.map((s) => [s.id, s])),
|
|
184
|
-
agentByStepId: Object.fromEntries(plan.steps.map((s) => [s.id, s.agent ?? "unknown"])),
|
|
185
|
-
resourcesByStepId: Object.fromEntries(plan.steps.map((s) => {
|
|
186
|
-
if (!s.resources) {
|
|
187
|
-
throw new Error(`Step "${s.id}" has no resources — validatePlan should have rejected this plan`);
|
|
188
|
-
}
|
|
189
|
-
return [s.id, s.resources];
|
|
190
|
-
})),
|
|
191
|
-
timeoutByStepId: Object.fromEntries(plan.steps.filter((s) => s.timeout !== undefined).map((s) => [s.id, s.timeout])),
|
|
192
|
-
budget: resourcePolicy?.budget,
|
|
193
|
-
runSession,
|
|
194
|
-
ownsMandate: authorization.ownsMandate, // oss-core-managed-ok
|
|
195
|
-
};
|
|
196
|
-
// (4) Dispatch the workflow. `workflowId = runId` — both are the same
|
|
197
|
-
// bare UUID. On failure after insert + authorize, revoke the authorization and
|
|
198
|
-
// mark the row failed.
|
|
199
|
-
try {
|
|
200
|
-
await runLauncher.launch(executeAnalysisWorkflow, { workflowId: runId }, workflowInput);
|
|
201
|
-
}
|
|
202
|
-
catch (err) {
|
|
203
|
-
await runAuthorizer.revoke(authorization, "workflow-start-failed").catch(() => { });
|
|
204
|
-
await updateRunStatus(pool, runId, "failed", "workflow start failed").match(() => { }, () => { });
|
|
205
|
-
throw err;
|
|
206
|
-
}
|
|
207
|
-
await emitRunCard(analysisId, runId);
|
|
208
|
-
return ok({ runId });
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* run_ephemeral — ad-hoc data exploration in a read-only sandbox.
|
|
3
|
-
*
|
|
4
|
-
* Authorizes the run at the async edge via the RunAuthorizer seam, then starts
|
|
5
|
-
* the ephemeral workflow through the RunLauncher seam and awaits its result
|
|
6
|
-
* inline within the chat turn. Chat disconnect cancels the run; the
|
|
7
|
-
* authorization is revoked on every terminal path. The workflow is never
|
|
8
|
-
* recovered — a turn-scoped exploration outliving its turn has no value.
|
|
9
|
-
*
|
|
10
|
-
* Available to: conversation-agent.
|
|
11
|
-
*/
|
|
12
|
-
import type { RunAuthorizer } from "../execution/run-authorizer.js";
|
|
13
|
-
import type { RunLauncher } from "../execution/run-launcher.js";
|
|
14
|
-
import { type EphemeralResult, type EphemeralWorkflowInput } from "../execution/ephemeral-runner.js";
|
|
15
|
-
export interface RunEphemeralToolDeps {
|
|
16
|
-
/** Registered ephemeral workflow callable. */
|
|
17
|
-
readonly workflow: (input: EphemeralWorkflowInput) => Promise<EphemeralResult>;
|
|
18
|
-
/** Authorizes the run at the async edge and revokes on the terminal path. */
|
|
19
|
-
readonly runAuthorizer: RunAuthorizer;
|
|
20
|
-
/** Starts the durable run — the durability engine stays behind this seam. */
|
|
21
|
-
readonly runLauncher: RunLauncher;
|
|
22
|
-
}
|
|
23
|
-
export interface RunEphemeralToolOutput {
|
|
24
|
-
readonly text: string;
|
|
25
|
-
readonly durationMs: number;
|
|
26
|
-
}
|
|
27
|
-
/** Build the `run_ephemeral` tool bound to the registered workflow + mint deps. */
|
|
28
|
-
export declare function createRunEphemeralTool(deps: RunEphemeralToolDeps): import("./define-tool.js").Tool<{
|
|
29
|
-
prompt: string;
|
|
30
|
-
}, {
|
|
31
|
-
text: string;
|
|
32
|
-
durationMs: number;
|
|
33
|
-
}>;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* run_ephemeral — ad-hoc data exploration in a read-only sandbox.
|
|
3
|
-
*
|
|
4
|
-
* Authorizes the run at the async edge via the RunAuthorizer seam, then starts
|
|
5
|
-
* the ephemeral workflow through the RunLauncher seam and awaits its result
|
|
6
|
-
* inline within the chat turn. Chat disconnect cancels the run; the
|
|
7
|
-
* authorization is revoked on every terminal path. The workflow is never
|
|
8
|
-
* recovered — a turn-scoped exploration outliving its turn has no value.
|
|
9
|
-
*
|
|
10
|
-
* Available to: conversation-agent.
|
|
11
|
-
*/
|
|
12
|
-
import { ok } from "neverthrow";
|
|
13
|
-
import { z } from "zod";
|
|
14
|
-
import { EPHEMERAL_WORKFLOW_PREFIX } from "../execution/ephemeral-runner.js";
|
|
15
|
-
import { generateExecutionId } from "../sandbox/execution-id.js";
|
|
16
|
-
import { defineTool } from "./define-tool.js";
|
|
17
|
-
const inputSchema = z.object({
|
|
18
|
-
prompt: z
|
|
19
|
-
.string()
|
|
20
|
-
.min(1)
|
|
21
|
-
.describe("What to compute. Be specific: which files to read, what analysis to " + "run, what output format to return (table, statistics, base64 plot)."),
|
|
22
|
-
});
|
|
23
|
-
/** Build the `run_ephemeral` tool bound to the registered workflow + mint deps. */
|
|
24
|
-
export function createRunEphemeralTool(deps) {
|
|
25
|
-
return defineTool({
|
|
26
|
-
id: "run_ephemeral",
|
|
27
|
-
description: "Run a quick computation on the analysis data in a read-only sandbox. " +
|
|
28
|
-
"Use for ad-hoc data exploration: inspect a CSV, compute statistics, " +
|
|
29
|
-
"generate plot data, preview transformations. The sandbox cannot " +
|
|
30
|
-
"create or save files — results are returned inline. For persistent " +
|
|
31
|
-
"analyses that produce artifacts, use generate_plan + executePlan instead.",
|
|
32
|
-
inputSchema,
|
|
33
|
-
execute: async (input, ctx) => {
|
|
34
|
-
const { session } = ctx;
|
|
35
|
-
if (session.scope.kind !== "analysis") {
|
|
36
|
-
throw new Error("run_ephemeral requires an analysis-scoped session — got " + session.scope.kind);
|
|
37
|
-
}
|
|
38
|
-
if (!session.auth) {
|
|
39
|
-
throw new Error("run_ephemeral: session is missing its auth capability");
|
|
40
|
-
}
|
|
41
|
-
const authorization = await deps.runAuthorizer.authorize({
|
|
42
|
-
auth: session.auth,
|
|
43
|
-
scope: session.scope,
|
|
44
|
-
provenance: session.provenance,
|
|
45
|
-
frame: { runId: "ephemeral", stepId: "ephemeral" },
|
|
46
|
-
});
|
|
47
|
-
const { runSession } = authorization;
|
|
48
|
-
const execId = generateExecutionId("ephemeral-executor");
|
|
49
|
-
const workflowId = `${EPHEMERAL_WORKFLOW_PREFIX}${execId}`;
|
|
50
|
-
try {
|
|
51
|
-
const outcome = await deps.runLauncher.launchAndAwait(deps.workflow, { workflowId }, { runSession, prompt: input.prompt }, { signal: ctx.signal });
|
|
52
|
-
if (outcome.status === "cancelled") {
|
|
53
|
-
return ok({ text: "(ephemeral exploration cancelled)", durationMs: 0 });
|
|
54
|
-
}
|
|
55
|
-
return ok({
|
|
56
|
-
text: outcome.result.text,
|
|
57
|
-
durationMs: outcome.result.durationMs,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
finally {
|
|
61
|
-
await deps.runAuthorizer.revoke(authorization, "ephemeral-completed").catch(() => { });
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
}
|