@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,25 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* inspectRun — inspect workflow runs for the current analysis.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Results are pull-only via this tool — the workflow does NOT write to the
|
|
9
|
-
* conversation thread on completion. The retired `run-result-writer` push
|
|
10
|
-
* payload (run status, step summaries, run synthesis, artifact paths) is
|
|
11
|
-
* surfaced here on demand: the run row + step `summaryPath` references +
|
|
12
|
-
* the `synthesisPath` for runs whose synthesis was produced let the
|
|
13
|
-
* conversation agent `read_file` the artefacts it needs.
|
|
4
|
+
* Results are pull-only: workflows never append completion messages to a
|
|
5
|
+
* conversation. List mode is active-first and paged. Targeted mode makes
|
|
6
|
+
* readiness explicit and can perform one bounded, abort-aware wait.
|
|
14
7
|
*/
|
|
8
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
15
9
|
import { ok } from "neverthrow";
|
|
16
10
|
import { z } from "zod";
|
|
17
|
-
import { queryRun, queryRunsByAnalysis, queryStepsByRun } from "../../state/index.js";
|
|
18
11
|
import { scopeResource } from "../../auth/types.js";
|
|
19
|
-
import { SYNTHESIS_STEP_ID } from "../../workspace/paths.js";
|
|
20
12
|
import { unwrapOrThrow } from "../../lib/result.js";
|
|
13
|
+
import { queryRun, queryRunsForInspection, queryStepsByRun } from "../../state/index.js";
|
|
14
|
+
import { SYNTHESIS_STEP_ID } from "../../workspace/paths.js";
|
|
21
15
|
import { defineTool } from "../define-tool.js";
|
|
22
|
-
|
|
16
|
+
const DEFAULT_PAGE_SIZE = 50;
|
|
17
|
+
const POLL_INTERVAL_MS = 1_000;
|
|
18
|
+
const systemClock = {
|
|
19
|
+
now: Date.now,
|
|
20
|
+
wait: (ms, signal) => sleep(ms, undefined, { signal }),
|
|
21
|
+
};
|
|
22
|
+
function isTerminal(status) {
|
|
23
|
+
return status === "completed" || status === "partial" || status === "failed" || status === "canceled";
|
|
24
|
+
}
|
|
25
|
+
function formatRun(r, verbose, exposePaths = isTerminal(r.status)) {
|
|
23
26
|
return {
|
|
24
27
|
runId: r.runId,
|
|
25
28
|
workflowName: r.workflowName,
|
|
@@ -27,74 +30,160 @@ function formatRun(r, verbose) {
|
|
|
27
30
|
startedAt: r.startedAt,
|
|
28
31
|
completedAt: r.completedAt,
|
|
29
32
|
planId: r.planId,
|
|
30
|
-
|
|
31
|
-
// result; a skipped/failed synthesis leaves no file, so pointing at a
|
|
32
|
-
// path would send the agent to a stale or absent artifact. The recorded
|
|
33
|
-
// outcome — surfaced as synthesisStatus (and synthesisReason when set) —
|
|
34
|
-
// lets a consumer tell "produced" from "skipped/failed/unknown" without
|
|
35
|
-
// reading a file.
|
|
36
|
-
synthesisPath: r.synthesisStatus === "produced" ? `runs/${r.runId}/synthesis.json` : null,
|
|
33
|
+
synthesisPath: exposePaths && r.synthesisStatus === "produced" ? `runs/${r.runId}/synthesis.json` : null,
|
|
37
34
|
synthesisStatus: r.synthesisStatus,
|
|
38
35
|
...(r.synthesisReason !== null ? { synthesisReason: r.synthesisReason } : {}),
|
|
39
36
|
...(verbose ? { error: r.error } : {}),
|
|
40
37
|
};
|
|
41
38
|
}
|
|
42
|
-
|
|
39
|
+
function formatSteps(runId, stepRows, verbose, exposePaths) {
|
|
40
|
+
return stepRows.map((s) => ({
|
|
41
|
+
stepId: s.stepId,
|
|
42
|
+
agentId: s.agentId,
|
|
43
|
+
wave: s.wave,
|
|
44
|
+
status: s.status,
|
|
45
|
+
...(exposePaths && s.status !== "pending" && s.status !== "skipped" && s.stepId !== SYNTHESIS_STEP_ID
|
|
46
|
+
? { summaryPath: `runs/${runId}/${s.stepId}/output/summary.md` }
|
|
47
|
+
: {}),
|
|
48
|
+
...(verbose
|
|
49
|
+
? {
|
|
50
|
+
durationMs: s.durationMs,
|
|
51
|
+
error: s.error,
|
|
52
|
+
attempts: s.attempts,
|
|
53
|
+
lastErrorClass: s.lastErrorClass,
|
|
54
|
+
finishReason: s.finishReason,
|
|
55
|
+
hitMaxSteps: s.hitMaxSteps,
|
|
56
|
+
}
|
|
57
|
+
: {}),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
const inputSchema = z
|
|
61
|
+
.object({
|
|
62
|
+
runId: z.string().optional().describe("Specific run to inspect. Omit to list runs."),
|
|
63
|
+
page: z.number().int().min(1).optional().describe("List page, starting at 1. Valid only without runId."),
|
|
64
|
+
pageSize: z.number().int().min(1).max(100).optional().describe("Rows per list page (1-100). Valid only without runId."),
|
|
65
|
+
waitForTerminalSeconds: z
|
|
66
|
+
.number()
|
|
67
|
+
.int()
|
|
68
|
+
.min(1)
|
|
69
|
+
.max(30)
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Wait up to this many seconds for a targeted running run to leave running state."),
|
|
72
|
+
includeDiagnostics: z
|
|
73
|
+
.boolean()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Include failure/retry telemetry: run.error and step.{durationMs,error,attempts,lastErrorClass,finishReason,hitMaxSteps}. Default false."),
|
|
76
|
+
})
|
|
77
|
+
.superRefine((input, refinement) => {
|
|
78
|
+
if (input.runId && (input.page !== undefined || input.pageSize !== undefined)) {
|
|
79
|
+
refinement.addIssue({
|
|
80
|
+
code: z.ZodIssueCode.custom,
|
|
81
|
+
message: "page and pageSize are valid only when runId is omitted",
|
|
82
|
+
path: input.page !== undefined ? ["page"] : ["pageSize"],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (!input.runId && input.waitForTerminalSeconds !== undefined) {
|
|
86
|
+
refinement.addIssue({
|
|
87
|
+
code: z.ZodIssueCode.custom,
|
|
88
|
+
message: "waitForTerminalSeconds requires runId",
|
|
89
|
+
path: ["waitForTerminalSeconds"],
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* Build the run-inspection tool. The optional clock is an internal testing
|
|
95
|
+
* seam for deterministic cutoff and transition coverage.
|
|
96
|
+
*/
|
|
97
|
+
export function createInspectRunTool(pool, clock = systemClock) {
|
|
43
98
|
return defineTool({
|
|
44
99
|
id: "inspect_run",
|
|
45
|
-
description: "Inspect workflow runs for this analysis. " +
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"Default response is lightweight — pass includeDiagnostics:true to add error/duration/retry telemetry.
|
|
49
|
-
|
|
50
|
-
inputSchema: z.object({
|
|
51
|
-
runId: z.string().optional().describe("Specific run to inspect. Omit to list all runs."),
|
|
52
|
-
includeDiagnostics: z
|
|
53
|
-
.boolean()
|
|
54
|
-
.optional()
|
|
55
|
-
.describe("Include failure/retry telemetry: run.error and step.{durationMs,error,attempts,lastErrorClass,finishReason,hitMaxSteps}. Default false."),
|
|
56
|
-
}),
|
|
100
|
+
description: "Inspect workflow runs for this analysis. Without a runId, returns an active-first paged list (running, suspended, then terminal history). " +
|
|
101
|
+
"With a runId, returns an explicit inspectionState and advertises output paths only after the run is terminal. " +
|
|
102
|
+
"For a user-directed check, waitForTerminalSeconds can wait once for 1-30 seconds; if the cutoff returns in_progress, stop polling for that turn. " +
|
|
103
|
+
"Default response is lightweight — pass includeDiagnostics:true to add error/duration/retry telemetry.",
|
|
104
|
+
inputSchema,
|
|
57
105
|
execute: async (input, ctx) => {
|
|
58
106
|
const resourceId = scopeResource(ctx.session.scope).resourceId;
|
|
59
107
|
const verbose = input.includeDiagnostics === true;
|
|
60
108
|
if (!input.runId) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
return ok({
|
|
109
|
+
const page = input.page ?? 1;
|
|
110
|
+
const pageSize = input.pageSize ?? DEFAULT_PAGE_SIZE;
|
|
111
|
+
const offset = (page - 1) * pageSize;
|
|
112
|
+
const result = unwrapOrThrow(await queryRunsForInspection(pool, resourceId, { limit: pageSize, offset }));
|
|
113
|
+
return ok({
|
|
114
|
+
runs: result.runs.map((run) => formatRun(run, verbose)),
|
|
115
|
+
total: result.total,
|
|
116
|
+
page,
|
|
117
|
+
pageSize,
|
|
118
|
+
hasMore: offset + result.runs.length < result.total,
|
|
119
|
+
});
|
|
66
120
|
}
|
|
67
|
-
const
|
|
121
|
+
const waitSeconds = input.waitForTerminalSeconds;
|
|
122
|
+
let run = unwrapOrThrow(await queryRun(pool, input.runId));
|
|
68
123
|
if (!run || run.analysisId !== resourceId) {
|
|
69
|
-
return ok({
|
|
124
|
+
return ok({
|
|
125
|
+
inspectionState: "not_found",
|
|
126
|
+
message: `Run ${input.runId} was not found in this analysis.`,
|
|
127
|
+
...(waitSeconds === undefined ? {} : { wait: { requestedSeconds: waitSeconds, cutoffReached: false } }),
|
|
128
|
+
});
|
|
70
129
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// `synthesis.json`, surfaced as the run's `synthesisPath`, not a
|
|
81
|
-
// `{stepId}/output/summary.md`. Emitting the per-step path for it would
|
|
82
|
-
// point the agent at a file that never exists.
|
|
83
|
-
...(s.status === "pending" || s.status === "skipped" || s.stepId === SYNTHESIS_STEP_ID
|
|
84
|
-
? {}
|
|
85
|
-
: { summaryPath: `runs/${input.runId}/${s.stepId}/output/summary.md` }),
|
|
86
|
-
...(verbose
|
|
87
|
-
? {
|
|
88
|
-
durationMs: s.durationMs,
|
|
89
|
-
error: s.error,
|
|
90
|
-
attempts: s.attempts,
|
|
91
|
-
lastErrorClass: s.lastErrorClass,
|
|
92
|
-
finishReason: s.finishReason,
|
|
93
|
-
hitMaxSteps: s.hitMaxSteps,
|
|
130
|
+
const selfWait = waitSeconds !== undefined && ctx.session.runFrame?.runId === input.runId;
|
|
131
|
+
let cutoffReached = false;
|
|
132
|
+
if (waitSeconds !== undefined && run.status === "running" && !selfWait) {
|
|
133
|
+
const deadline = clock.now() + waitSeconds * 1_000;
|
|
134
|
+
while (run.status === "running") {
|
|
135
|
+
const remaining = deadline - clock.now();
|
|
136
|
+
if (remaining <= 0) {
|
|
137
|
+
cutoffReached = true;
|
|
138
|
+
break;
|
|
94
139
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
140
|
+
await clock.wait(Math.min(POLL_INTERVAL_MS, remaining), ctx.signal);
|
|
141
|
+
run = unwrapOrThrow(await queryRun(pool, input.runId));
|
|
142
|
+
if (!run || run.analysisId !== resourceId) {
|
|
143
|
+
return ok({
|
|
144
|
+
inspectionState: "not_found",
|
|
145
|
+
message: `Run ${input.runId} was not found in this analysis.`,
|
|
146
|
+
wait: { requestedSeconds: waitSeconds, cutoffReached: false },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const terminal = isTerminal(run.status);
|
|
152
|
+
const stepRows = unwrapOrThrow(await queryStepsByRun(pool, input.runId));
|
|
153
|
+
const steps = formatSteps(input.runId, stepRows, verbose, terminal);
|
|
154
|
+
const wait = waitSeconds === undefined ? {} : { wait: { requestedSeconds: waitSeconds, cutoffReached } };
|
|
155
|
+
if (run.status === "running") {
|
|
156
|
+
const message = selfWait
|
|
157
|
+
? "This run is still in progress. Results are not ready, and the enclosing workflow cannot finish while its current step waits for itself."
|
|
158
|
+
: cutoffReached
|
|
159
|
+
? "This run is still in progress after the requested wait cutoff. Results are not ready; stop polling for this turn."
|
|
160
|
+
: "This run is in progress. Results are not ready.";
|
|
161
|
+
return ok({
|
|
162
|
+
inspectionState: "in_progress",
|
|
163
|
+
message,
|
|
164
|
+
run: formatRun(run, verbose, false),
|
|
165
|
+
steps,
|
|
166
|
+
elapsedMs: Math.max(0, clock.now() - Date.parse(run.startedAt)),
|
|
167
|
+
...wait,
|
|
168
|
+
...(selfWait ? { selfWaitPrevented: true } : {}),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (run.status === "suspended_insufficient_funds") {
|
|
172
|
+
return ok({
|
|
173
|
+
inspectionState: "suspended",
|
|
174
|
+
message: "This run is suspended and will not progress until it is resumed.",
|
|
175
|
+
run: formatRun(run, verbose, false),
|
|
176
|
+
steps,
|
|
177
|
+
...wait,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return ok({
|
|
181
|
+
inspectionState: "terminal",
|
|
182
|
+
message: `This run is terminal with status ${run.status}.`,
|
|
183
|
+
run: formatRun(run, verbose, true),
|
|
184
|
+
steps,
|
|
185
|
+
...wait,
|
|
186
|
+
});
|
|
98
187
|
},
|
|
99
188
|
});
|
|
100
189
|
}
|
|
@@ -22,14 +22,11 @@ import { literatureReviewerPrompt } from "../../prompts/literature-reviewer.js";
|
|
|
22
22
|
import { composeSystemPrompt } from "../../agents/system-prompt.js";
|
|
23
23
|
import { forSubAgent } from "../../auth/types.js";
|
|
24
24
|
import { defineTool } from "../define-tool.js";
|
|
25
|
-
import { createNcbiTools } from "../bio/keys.js";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { searchBgeeExpressionTool } from "../bio/search-bgee-expression.js";
|
|
29
|
-
import { createSearchDgidbTool } from "../bio/search-dgidb.js";
|
|
25
|
+
import { createChemDbTools, createNcbiTools } from "../bio/keys.js";
|
|
26
|
+
import { genePreclinicalProfileTool } from "../bio/gene-preclinical-profile.js";
|
|
27
|
+
import { lookupAnnotationTool } from "../bio/lookup-annotation.js";
|
|
30
28
|
import { searchGeneTool } from "../bio/search-gene.js";
|
|
31
29
|
import { searchInteractionsTool } from "../bio/search-interactions.js";
|
|
32
|
-
import { searchPathwayTool } from "../bio/search-pathway.js";
|
|
33
30
|
/** Sub-agent identity — appended to `callPath`, set as `agentId`. */
|
|
34
31
|
const AGENT_ID = "literature-reviewer";
|
|
35
32
|
/** Multi-tool research budget — search → read → synthesize over many genes. */
|
|
@@ -37,15 +34,14 @@ const REVIEWER_MAX_ITERATIONS = 30;
|
|
|
37
34
|
/** Build the `literature_reviewer` delegation tool bound to its provider. */
|
|
38
35
|
export function createLiteratureReviewerTool(deps) {
|
|
39
36
|
const ncbi = createNcbiTools(deps.bioKeys);
|
|
37
|
+
const chemDb = createChemDbTools(deps.bioKeys, { ...(deps.logger ? { logger: deps.logger } : {}) });
|
|
40
38
|
const reviewerTools = [
|
|
41
39
|
searchGeneTool,
|
|
42
|
-
|
|
43
|
-
lookupGoTermTool,
|
|
40
|
+
lookupAnnotationTool,
|
|
44
41
|
searchInteractionsTool,
|
|
45
42
|
ncbi.pubmed,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
getImpcKoProfileTool,
|
|
43
|
+
chemDb.drugGeneInteractions,
|
|
44
|
+
genePreclinicalProfileTool,
|
|
49
45
|
];
|
|
50
46
|
const agent = {
|
|
51
47
|
id: AGENT_ID,
|
|
@@ -115,6 +115,11 @@ export interface ExecuteAnalysisInput {
|
|
|
115
115
|
* dependency-satisfied step starts immediately — the legacy fan-out.
|
|
116
116
|
*/
|
|
117
117
|
readonly budget?: MachineBudget;
|
|
118
|
+
/**
|
|
119
|
+
* Replay-stable run-level synthesis decision. Absent preserves the legacy
|
|
120
|
+
* behavior for workflows persisted before this field existed.
|
|
121
|
+
*/
|
|
122
|
+
readonly synthesisEnabled?: boolean;
|
|
118
123
|
/**
|
|
119
124
|
* Durable `RunSession` minted at the async edge by `executePlan`.
|
|
120
125
|
* Carries the run-authorization credential, identity, scope, and `runFrame.runId`.
|
|
@@ -204,6 +209,49 @@ export type RunProvenanceEvent = {
|
|
|
204
209
|
/** `atMs − run_started.atMs`: the workflow-observed run span in ms. */
|
|
205
210
|
durationMs: number;
|
|
206
211
|
};
|
|
212
|
+
/**
|
|
213
|
+
* A step's in-run display state. Wider than the ledger's `StepExecutionStatus`: `queued` is a
|
|
214
|
+
* scheduler-only condition (dependency-satisfied but held for budget capacity) that never reaches a
|
|
215
|
+
* database row, and `skipped` is asserted mid-run for a doomed dependent whose ledger row stays
|
|
216
|
+
* `pending` until the terminal sweep.
|
|
217
|
+
*/
|
|
218
|
+
export type StepRuntimeStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
|
|
219
|
+
/**
|
|
220
|
+
* One step's state inside a {@link RunObservation}. `id` is the plan slug the ledger and the
|
|
221
|
+
* dependency edges use; `name` is the human phrase the plan author wrote, which is the only field
|
|
222
|
+
* that says what the step is FOR. `durationMs` and `error` appear only once the step has settled
|
|
223
|
+
* in a way that produced them.
|
|
224
|
+
*/
|
|
225
|
+
export interface RunStepObservation {
|
|
226
|
+
readonly id: string;
|
|
227
|
+
readonly name: string;
|
|
228
|
+
readonly agent: string;
|
|
229
|
+
readonly status: StepRuntimeStatus;
|
|
230
|
+
readonly durationMs?: number;
|
|
231
|
+
readonly error?: string;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* A whole-run snapshot handed to {@link ExecuteAnalysisDeps.observeRun}.
|
|
235
|
+
*
|
|
236
|
+
* Deliberately a SNAPSHOT rather than a transition event. The observer is invoked from the
|
|
237
|
+
* workflow body, so DBOS re-execution on recovery re-fires the whole sequence; a re-fired snapshot
|
|
238
|
+
* is idempotent for any consumer that renders from the newest one it has seen, whereas re-fired
|
|
239
|
+
* granular events would force every consumer to rebuild ordering and dedupe by identity. A
|
|
240
|
+
* consumer that misses an invocation loses nothing permanent — the next transition restates the
|
|
241
|
+
* full truth.
|
|
242
|
+
*
|
|
243
|
+
* Derived aggregates (completion counts, run duration) are deliberately ABSENT. They are
|
|
244
|
+
* computable from `steps` and recorded authoritatively on the run's ledger row; carrying them here
|
|
245
|
+
* would mint a second source that can disagree with the ledger a host also reads.
|
|
246
|
+
*/
|
|
247
|
+
export interface RunObservation {
|
|
248
|
+
readonly runId: string;
|
|
249
|
+
readonly analysisId: string;
|
|
250
|
+
/** `running` for every mid-flight snapshot; the derived terminal status on the last one. */
|
|
251
|
+
readonly status: ExecuteAnalysisFinalStatus;
|
|
252
|
+
/** Every plan step, including ones that have not started — never a delta. */
|
|
253
|
+
readonly steps: readonly RunStepObservation[];
|
|
254
|
+
}
|
|
207
255
|
/**
|
|
208
256
|
* Construction-time deps for the parent workflow. The order-of-operations is
|
|
209
257
|
* the body's own: it brackets the run, dispatches children, and synthesizes
|
|
@@ -230,11 +278,6 @@ export interface ExecuteAnalysisDeps {
|
|
|
230
278
|
readonly bioKeys: BioToolKeys;
|
|
231
279
|
/** Run-level billing-bracket seam (managed: external bracket; OSS: no-op). */
|
|
232
280
|
readonly runCharge: RunCharge;
|
|
233
|
-
/**
|
|
234
|
-
* When false, skip run-level synthesis entirely (findings stay empty).
|
|
235
|
-
* Config, not a seam. Defaults to true.
|
|
236
|
-
*/
|
|
237
|
-
readonly synthesisEnabled?: boolean;
|
|
238
281
|
/** Run-authorization seam — the terminal path revokes through `revoke`. */
|
|
239
282
|
readonly runAuthorizer: RunAuthorizer;
|
|
240
283
|
/**
|
|
@@ -247,6 +290,26 @@ export interface ExecuteAnalysisDeps {
|
|
|
247
290
|
* guarded so a throwing observer never fails the run.
|
|
248
291
|
*/
|
|
249
292
|
readonly emitProvenance?: (event: RunProvenanceEvent) => void;
|
|
293
|
+
/**
|
|
294
|
+
* Optional, fire-and-forget observation of the run's live shape, for a host driving a UI.
|
|
295
|
+
*
|
|
296
|
+
* Independent of {@link emitProvenance} in every direction: neither is implemented in terms of
|
|
297
|
+
* the other, they share no payload, and supplying one does not imply the other. They exist
|
|
298
|
+
* separately because provenance closes a signed, hash-chained record under a single-writer
|
|
299
|
+
* lock, while this is a lossy-tolerant display channel — coupling them would put a UI repaint
|
|
300
|
+
* behind the chain's write discipline and force provenance to carry step names and agent ids it
|
|
301
|
+
* has no reason to record.
|
|
302
|
+
*
|
|
303
|
+
* Invoked directly in the workflow body (NOT wrapped in `DBOS.runStep`) for the same reason
|
|
304
|
+
* `emitProvenance` is: body re-execution on recovery must re-fire it, and a cached step would
|
|
305
|
+
* suppress that. Idempotency comes free for rendering because the payload is a whole-run
|
|
306
|
+
* snapshot; a host taking a DURABLE side effect on one must key it by run id and status itself.
|
|
307
|
+
*
|
|
308
|
+
* Synchronous by signature (`void`, never a promise) so a host needing I/O has to dispatch it
|
|
309
|
+
* rather than await it inside the body's critical path. Every call site is guarded, so a
|
|
310
|
+
* throwing observer never fails the run.
|
|
311
|
+
*/
|
|
312
|
+
readonly observeRun?: (observation: RunObservation) => void;
|
|
250
313
|
}
|
|
251
314
|
/**
|
|
252
315
|
* Project the sandbox-step input handed to each child. The parent owns the
|
|
@@ -97,6 +97,52 @@ function emitProvenanceGuarded(deps, event) {
|
|
|
97
97
|
logger.error("emitProvenance threw", { runId: event.runId, event: event.type, ...logger.errorFields(err) });
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Build the whole-run snapshot from the workflow input and the scheduler's live step state.
|
|
102
|
+
*
|
|
103
|
+
* Pure, so every emission point produces an identically-shaped payload from one place — a second
|
|
104
|
+
* construction path is exactly how "a transition happened" acquires two definitions that drift.
|
|
105
|
+
* The human `name` joins through `input.planStepById` because `input.steps` is the scheduler's
|
|
106
|
+
* narrow `{id, depends_on}` projection and carries no plan vocabulary.
|
|
107
|
+
*/
|
|
108
|
+
function buildRunObservation(args) {
|
|
109
|
+
const { input, runId, status, stepStates } = args;
|
|
110
|
+
return {
|
|
111
|
+
runId,
|
|
112
|
+
analysisId: input.analysisId,
|
|
113
|
+
status,
|
|
114
|
+
steps: input.steps.map((s) => {
|
|
115
|
+
const rt = stepStates.get(s.id);
|
|
116
|
+
return {
|
|
117
|
+
id: s.id,
|
|
118
|
+
name: input.planStepById[s.id]?.name ?? s.id,
|
|
119
|
+
agent: input.agentByStepId[s.id] ?? "unknown",
|
|
120
|
+
// A step absent from the map has not been reached yet; `pending` is its honest state.
|
|
121
|
+
status: rt?.status ?? "pending",
|
|
122
|
+
...(rt?.durationMs !== undefined ? { durationMs: rt.durationMs } : {}),
|
|
123
|
+
...(rt?.error !== undefined ? { error: rt.error } : {}),
|
|
124
|
+
};
|
|
125
|
+
}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fire the optional run observer, isolating a throwing host callback from the workflow.
|
|
130
|
+
*
|
|
131
|
+
* Deliberately a sibling of {@link emitProvenanceGuarded} rather than a shared helper: the two
|
|
132
|
+
* seams carry unrelated payloads and must stay independently removable, and one shared guard would
|
|
133
|
+
* have to pick a single logger namespace, making it lie about whichever seam it is not named for.
|
|
134
|
+
*/
|
|
135
|
+
function observeRunGuarded(deps, observation) {
|
|
136
|
+
if (!deps.observeRun)
|
|
137
|
+
return;
|
|
138
|
+
const logger = (deps.logger ?? createNoopLogger()).named("executeAnalysis.observe");
|
|
139
|
+
try {
|
|
140
|
+
deps.observeRun(observation);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
logger.error("observeRun threw", { runId: observation.runId, status: observation.status, ...logger.errorFields(err) });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
100
146
|
/**
|
|
101
147
|
* Project the sandbox-step input handed to each child. The parent owns the
|
|
102
148
|
* level computation and the seed (`prompt`, composed by `composeStepSeed` at
|
|
@@ -342,7 +388,7 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
342
388
|
// `pending` and the terminal sweep finalizes it to `skipped` — honest
|
|
343
389
|
// ("never ran, never will"), like any never-dispatched DAG step. Its wave
|
|
344
390
|
// sits after every DAG level so ledger-ordered readers render it last.
|
|
345
|
-
const synthesisEnabled =
|
|
391
|
+
const synthesisEnabled = input.synthesisEnabled ?? true;
|
|
346
392
|
const synthesisWave = Math.max(-1, ...levels.values()) + 1;
|
|
347
393
|
await DBOS.runStep(async () => {
|
|
348
394
|
const dagRows = input.steps.map((step) => ({
|
|
@@ -379,6 +425,10 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
379
425
|
stepCount: input.steps.length,
|
|
380
426
|
atMs: startedAtMs,
|
|
381
427
|
});
|
|
428
|
+
// Opening snapshot: every step pending. The scheduler's own map does not exist yet, and an
|
|
429
|
+
// empty one yields exactly that — so a host has the run's full shape before the first dispatch
|
|
430
|
+
// rather than learning the step list from whichever transition happens to land first.
|
|
431
|
+
observeRunGuarded(deps, buildRunObservation({ input, runId, status: "running", stepStates: new Map() }));
|
|
382
432
|
// (2-4) Scheduler loop + failure isolation + pause cascade.
|
|
383
433
|
const final = await runSchedulerLoop({
|
|
384
434
|
input,
|
|
@@ -403,10 +453,8 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
403
453
|
// recovered replay reuses the original instants (same rule as `startedAtMs`).
|
|
404
454
|
const synthStartedAtMs = await DBOS.now();
|
|
405
455
|
// Mark the seeded `synthesis` row running. The same upsert the DAG children
|
|
406
|
-
// use: it stamps started_at, and it
|
|
407
|
-
//
|
|
408
|
-
// redeploy) — the mark self-heals rather than trusting the seed's snapshot
|
|
409
|
-
// of the config. Log-don't-fail: a progress row must never fail an
|
|
456
|
+
// use: it stamps started_at, and it creates the row outright if a legacy
|
|
457
|
+
// persisted input did not seed it. Log-don't-fail: a progress row must never fail an
|
|
410
458
|
// otherwise-healthy run. Cancellation still re-propagates — it is not a
|
|
411
459
|
// write failure, and swallowing it here would only defer it one operation.
|
|
412
460
|
try {
|
|
@@ -492,6 +540,11 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
492
540
|
synthesisOutcome,
|
|
493
541
|
deps,
|
|
494
542
|
});
|
|
543
|
+
// Terminal snapshot, fired here rather than inside `collectAndComplete` because this is the
|
|
544
|
+
// first point where BOTH the derived final status and the scheduler's final step map are in
|
|
545
|
+
// hand. It precedes the budget self-cancel below on purpose: that branch raises out of the
|
|
546
|
+
// body, so an observer placed after it would never see a budget-paused run's last state.
|
|
547
|
+
observeRunGuarded(deps, buildRunObservation({ input, runId, status: result.status, stepStates: final.stepStates }));
|
|
495
548
|
// Synthesis failure takes priority over the budget-exceeded cascade: a run
|
|
496
549
|
// whose synthesis threw is definitively failed (ERROR), not a resumable
|
|
497
550
|
// budget pause. Only self-cancel when synthesis succeeded.
|
|
@@ -604,7 +657,14 @@ async function runSchedulerLoop(args) {
|
|
|
604
657
|
const rt = stepRuntime.get(s.id);
|
|
605
658
|
const entry = {
|
|
606
659
|
id: s.id,
|
|
607
|
-
|
|
660
|
+
// `input.steps` is the SCHEDULER's projection — `{id, depends_on}` and nothing
|
|
661
|
+
// else — so the human name has to be joined from the snapshotted plan step. A
|
|
662
|
+
// consumer reading `name` is reading it to say what the step is FOR, which the
|
|
663
|
+
// id (a `T{track}S{step}` slug) cannot answer. Falling back to the id keeps the
|
|
664
|
+
// field populated for a step missing from the snapshot rather than emitting an
|
|
665
|
+
// empty label; `planStepById` is complete by contract (dispatch throws on a
|
|
666
|
+
// miss), so the fallback is unreachable in practice.
|
|
667
|
+
name: input.planStepById[s.id]?.name ?? s.id,
|
|
608
668
|
agent: input.agentByStepId[s.id] ?? "unknown",
|
|
609
669
|
status: rt.status,
|
|
610
670
|
level: levels.get(s.id) ?? 0,
|
|
@@ -614,9 +674,18 @@ async function runSchedulerLoop(args) {
|
|
|
614
674
|
entry.durationMs = rt.durationMs;
|
|
615
675
|
if (rt.error !== undefined)
|
|
616
676
|
entry.error = rt.error;
|
|
677
|
+
// `artifactCount` and `summary` are declared on `DagStepState` and deliberately not
|
|
678
|
+
// set: the parent holds neither at snapshot time, and a placeholder would make a
|
|
679
|
+
// consumer's rendering confidently wrong rather than honestly incomplete.
|
|
617
680
|
return entry;
|
|
618
681
|
}),
|
|
619
682
|
});
|
|
683
|
+
// The host observer rides the DAG emission rather than getting its own instrumentation
|
|
684
|
+
// points: these call sites already ARE the complete set of run-state transitions, and a
|
|
685
|
+
// second set would drift from this one. Status is `running` here by construction — the
|
|
686
|
+
// scheduler loop only emits while it is still scheduling; the terminal snapshot is fired by
|
|
687
|
+
// the body once `collectAndComplete` has derived the final status.
|
|
688
|
+
observeRunGuarded(deps, buildRunObservation({ input, runId, status: "running", stepStates: stepRuntime }));
|
|
620
689
|
};
|
|
621
690
|
const dbosParentId = DBOS.workflowID ?? workflowId;
|
|
622
691
|
const dispatchReady = async () => {
|
|
@@ -843,7 +912,7 @@ async function runSchedulerLoop(args) {
|
|
|
843
912
|
});
|
|
844
913
|
}
|
|
845
914
|
await drainBudgetExceededNotifications(budgetExceededChildIds);
|
|
846
|
-
return { completed, failed, canceled, budgetExceeded, failureReason };
|
|
915
|
+
return { completed, failed, canceled, budgetExceeded, failureReason, stepStates: stepRuntime };
|
|
847
916
|
}
|
|
848
917
|
async function drainBudgetExceededNotifications(childIds) {
|
|
849
918
|
while (true) {
|
|
@@ -33,7 +33,7 @@ import { unwrapOrThrow } from "../lib/result.js";
|
|
|
33
33
|
import { isBudgetExceeded } from "../loop/budget-exceeded.js";
|
|
34
34
|
import { runAgent } from "../loop/run-agent.js";
|
|
35
35
|
import { durableStep } from "../loop/run-step.js";
|
|
36
|
-
import { activityForTool, applyTreeDelta, isChatDataPart, sandboxTreeDelta } from "../sandbox/sandbox-step-translate.js";
|
|
36
|
+
import { activityForTool, applyTreeDelta, isChatDataPart, sandboxTreeDelta, stepPartId } from "../sandbox/sandbox-step-translate.js";
|
|
37
37
|
import { forSubAgent } from "../auth/types.js";
|
|
38
38
|
import { walkStepArtifacts } from "../execution/post-step.js";
|
|
39
39
|
import { collectStepOutputs, generateStepFileMetadata, generateStepSummaryAndWrite, reconcileAndRegisterStepArtifacts, vectorIndexStepOutputs, } from "../execution/post-step-pipeline.js";
|
|
@@ -61,16 +61,6 @@ function nextFunctionIdFactory() {
|
|
|
61
61
|
let n = 0;
|
|
62
62
|
return () => `fn-${(n++).toString(36)}`;
|
|
63
63
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Stable reconciliation id for a step's reconciling parts
|
|
66
|
-
* (`data-step-activity`, `data-step-file-tree`). One id per (runId, stepId)
|
|
67
|
-
* so the run-stream fold collapses every phase transition latest-wins onto
|
|
68
|
-
* a single frame. The client keys these by `stepId`, but the server fold
|
|
69
|
-
* keys by part `id`, so the id MUST be unique per step within the run.
|
|
70
|
-
*/
|
|
71
|
-
function stepPartId(kind, runId, stepId) {
|
|
72
|
-
return `${kind}-${runId}-${stepId}`;
|
|
73
|
-
}
|
|
74
64
|
/**
|
|
75
65
|
* Map an internal step failure to a user-safe string. Internal detail (file
|
|
76
66
|
* paths, content hashes, managed-root rejection reasons, stack traces) stays in the pod
|
|
@@ -43,9 +43,9 @@ export declare const DrugsInClassOutputSchema: z.ZodObject<{
|
|
|
43
43
|
firstApproval: z.ZodNullable<z.ZodNumber>;
|
|
44
44
|
moleculeType: z.ZodNullable<z.ZodString>;
|
|
45
45
|
sources: z.ZodArray<z.ZodEnum<{
|
|
46
|
-
chembl: "chembl";
|
|
47
46
|
dgidb: "dgidb";
|
|
48
47
|
drugbank: "drugbank";
|
|
48
|
+
chembl: "chembl";
|
|
49
49
|
}>>;
|
|
50
50
|
}, z.core.$strip>>;
|
|
51
51
|
total: z.ZodNumber;
|
|
@@ -1707,8 +1707,8 @@ export declare const Phase4OutputSchema: z.ZodObject<{
|
|
|
1707
1707
|
medium: "medium";
|
|
1708
1708
|
low: "low";
|
|
1709
1709
|
absent: "absent";
|
|
1710
|
-
not_loaded: "not_loaded";
|
|
1711
1710
|
no_data: "no_data";
|
|
1711
|
+
not_loaded: "not_loaded";
|
|
1712
1712
|
}>;
|
|
1713
1713
|
}, z.core.$strip>>;
|
|
1714
1714
|
per_species_coverage: z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
@@ -53,9 +53,9 @@ export declare const Phase2AggregateInputSchema: z.ZodObject<{
|
|
|
53
53
|
firstApproval: z.ZodNullable<z.ZodNumber>;
|
|
54
54
|
moleculeType: z.ZodNullable<z.ZodString>;
|
|
55
55
|
sources: z.ZodArray<z.ZodEnum<{
|
|
56
|
-
chembl: "chembl";
|
|
57
56
|
dgidb: "dgidb";
|
|
58
57
|
drugbank: "drugbank";
|
|
58
|
+
chembl: "chembl";
|
|
59
59
|
}>>;
|
|
60
60
|
}, z.core.$strip>>;
|
|
61
61
|
total: z.ZodNumber;
|
|
@@ -672,9 +672,9 @@ export declare const Phase2BundleSchema: z.ZodObject<{
|
|
|
672
672
|
firstApproval: z.ZodNullable<z.ZodNumber>;
|
|
673
673
|
moleculeType: z.ZodNullable<z.ZodString>;
|
|
674
674
|
sources: z.ZodArray<z.ZodEnum<{
|
|
675
|
-
chembl: "chembl";
|
|
676
675
|
dgidb: "dgidb";
|
|
677
676
|
drugbank: "drugbank";
|
|
677
|
+
chembl: "chembl";
|
|
678
678
|
}>>;
|
|
679
679
|
}, z.core.$strip>>;
|
|
680
680
|
total: z.ZodNumber;
|
|
@@ -757,9 +757,9 @@ export declare const Phase3BundleSchema: z.ZodObject<{
|
|
|
757
757
|
firstApproval: z.ZodNullable<z.ZodNumber>;
|
|
758
758
|
moleculeType: z.ZodNullable<z.ZodString>;
|
|
759
759
|
sources: z.ZodArray<z.ZodEnum<{
|
|
760
|
-
chembl: "chembl";
|
|
761
760
|
dgidb: "dgidb";
|
|
762
761
|
drugbank: "drugbank";
|
|
762
|
+
chembl: "chembl";
|
|
763
763
|
}>>;
|
|
764
764
|
}, z.core.$strip>>;
|
|
765
765
|
total: z.ZodNumber;
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ephemeral Executor — read-only sandbox agent for quick computations.
|
|
3
|
-
* Cannot create files; step conventions don't apply.
|
|
4
|
-
*/
|
|
5
|
-
import type { AgentDefinition } from "../../loop/types.js";
|
|
6
|
-
import { type SandboxAgentDeps } from "./shared.js";
|
|
7
|
-
import type { AgentMeta } from "./types.js";
|
|
8
|
-
export declare const meta: AgentMeta;
|
|
9
|
-
export declare function createEphemeralExecutorAgent(deps: SandboxAgentDeps): AgentDefinition;
|