@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
package/dist/providers/errors.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* re-authenticating fixes it — which is a different remedy from every other
|
|
16
16
|
* non-retryable 4xx, so it is a different kind.
|
|
17
17
|
*/
|
|
18
|
+
import { redactSecrets } from "../input-sanitization.js";
|
|
18
19
|
/**
|
|
19
20
|
* Structural guard for an already-constructed `ProviderError` value. A
|
|
20
21
|
* `ProviderError` is a plain object, not an `Error`, so it cannot be
|
|
@@ -71,7 +72,67 @@ export function toProviderError(e, workload) {
|
|
|
71
72
|
cause: e,
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
// The `provider` arm composes like its three siblings rather than forwarding
|
|
76
|
+
// the SDK message verbatim. It has to: when a 4xx body does not parse against
|
|
77
|
+
// the configured provider's error schema, the AI SDK falls back to
|
|
78
|
+
// `response.statusText`, so the "detail" is a bare HTTP reason phrase —
|
|
79
|
+
// `"Bad Request"` — that names neither the call nor the cause, while the
|
|
80
|
+
// status, the workload, and the body the SDK captured are all still on the
|
|
81
|
+
// `cause` chain right here.
|
|
82
|
+
//
|
|
83
|
+
// Composed strictly AFTER `classifyProviderError` has returned, so message
|
|
84
|
+
// text can never become a classification input: the harness-providers spec
|
|
85
|
+
// fixes classification on the HTTP status alone.
|
|
86
|
+
const status = extractStatus(e);
|
|
87
|
+
const lead = status === undefined ? `Provider call failed for ${workload}` : `Provider call failed for ${workload} (HTTP ${status})`;
|
|
88
|
+
// A transport that carries no reason phrase (an HTTP/2 hop yields
|
|
89
|
+
// `statusText === ""`) leaves `detail` empty; appending it regardless would
|
|
90
|
+
// trail a bare `": "` on an otherwise complete message.
|
|
91
|
+
const reason = detail.trim();
|
|
92
|
+
const diagnosed = reason ? `${lead}: ${reason}` : lead;
|
|
93
|
+
const body = extractResponseBody(e);
|
|
94
|
+
return {
|
|
95
|
+
type: "provider",
|
|
96
|
+
retryable,
|
|
97
|
+
// The excerpt trails deliberately — workload and status lead, so a
|
|
98
|
+
// downstream truncation (`profileFailureReason` cuts the line at 200)
|
|
99
|
+
// eats the least diagnostic content first.
|
|
100
|
+
message: body ? `${diagnosed} — response body: ${excerptResponseBody(body)}` : diagnosed,
|
|
101
|
+
cause: e,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Max characters of a captured provider response body carried in a message.
|
|
106
|
+
*
|
|
107
|
+
* Derived, not picked: the tightest downstream consumer (`profileFailureReason`,
|
|
108
|
+
* `tasks/data-profile.ts`) truncates the whole line at 200, and the lead this
|
|
109
|
+
* excerpt trails — a workload label plus `HTTP <status>` plus a reason phrase —
|
|
110
|
+
* runs to roughly 80. 120 is therefore the largest round value that cannot evict
|
|
111
|
+
* that lead.
|
|
112
|
+
*
|
|
113
|
+
* Deliberately NOT shared with that consumer's `PROFILE_ERROR_MAX_LEN`: that one
|
|
114
|
+
* bounds a `varchar` ledger column, this one bounds a message many non-ledger
|
|
115
|
+
* consumers read, and coupling them would make either one unmovable.
|
|
116
|
+
*/
|
|
117
|
+
const PROVIDER_BODY_EXCERPT_MAX_LEN = 120;
|
|
118
|
+
/**
|
|
119
|
+
* Single-lined, secret-redacted, length-capped rendering of a captured response body. Bounding happens
|
|
120
|
+
* here rather than at a consumer because most `ProviderError` consumers truncate nothing at all, and the
|
|
121
|
+
* one that does would let an unbounded body crowd out the workload and status ahead of it.
|
|
122
|
+
*
|
|
123
|
+
* The body is an UNTRUSTED upstream/proxy payload, and this excerpt lands verbatim in the ledger's
|
|
124
|
+
* `data_profile_error` (surfaced to the UI) and the logs, whereas the composed lead does not — so
|
|
125
|
+
* secrets are redacted here and nowhere else on the message. Redaction runs on the FULL body before
|
|
126
|
+
* truncation: a token straddling the cut would otherwise be sliced into an unmatchable fragment that
|
|
127
|
+
* leaks. `redactSecrets` matches only prefixed formats (API keys, JWTs, bearer tokens, connection
|
|
128
|
+
* strings) and is safe on biological data, so a legitimate error body passes through intact.
|
|
129
|
+
*/
|
|
130
|
+
function excerptResponseBody(body) {
|
|
131
|
+
const singleLine = redactSecrets(body).replace(/\s+/g, " ").trim();
|
|
132
|
+
// Slice by CODE POINT, not UTF-16 unit: a raw byte body can carry astral characters, and a plain
|
|
133
|
+
// `.slice` could bisect a surrogate pair into a lone half that renders as U+FFFD.
|
|
134
|
+
const chars = [...singleLine];
|
|
135
|
+
return chars.length > PROVIDER_BODY_EXCERPT_MAX_LEN ? chars.slice(0, PROVIDER_BODY_EXCERPT_MAX_LEN - 1).join("") + "…" : singleLine;
|
|
75
136
|
}
|
|
76
137
|
/** Max links walked on the `cause` chain looking for a structured status. */
|
|
77
138
|
const MAX_CAUSE_HOPS = 5;
|
|
@@ -88,8 +149,13 @@ const CONNECTION_ERROR_CODES = new Set([
|
|
|
88
149
|
"UND_ERR_SOCKET",
|
|
89
150
|
]);
|
|
90
151
|
const CONNECTION_ERROR_PATTERN = /fetch failed|socket hang up|network error|connection (?:refused|reset|error|closed)|econnrefused|enotfound|etimedout|terminated/i;
|
|
91
|
-
/**
|
|
92
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Walk the `cause` chain for the first numeric HTTP status. The single status
|
|
154
|
+
* walker: `classifyProviderError` keys on what this returns, so a caller asking
|
|
155
|
+
* "did the provider layer have a status to classify on?" must ask it here rather
|
|
156
|
+
* than re-implement the traversal.
|
|
157
|
+
*/
|
|
158
|
+
export function extractStatus(err) {
|
|
93
159
|
let cursor = err;
|
|
94
160
|
for (let i = 0; i < MAX_CAUSE_HOPS && cursor; i++) {
|
|
95
161
|
const e = cursor;
|
|
@@ -101,6 +167,25 @@ function extractStatus(err) {
|
|
|
101
167
|
}
|
|
102
168
|
return undefined;
|
|
103
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Walk the `cause` chain for the first captured provider response body.
|
|
172
|
+
*
|
|
173
|
+
* This is what recovers a proxy-minted or otherwise non-conforming error body:
|
|
174
|
+
* the AI SDK keeps the raw bytes on `APICallError.responseBody` even when its
|
|
175
|
+
* own parse against the provider's error schema fails and its `message` degrades
|
|
176
|
+
* to the HTTP reason phrase. A blank body is treated as absent — an empty
|
|
177
|
+
* `— response body:` segment says less than no segment at all.
|
|
178
|
+
*/
|
|
179
|
+
function extractResponseBody(err) {
|
|
180
|
+
let cursor = err;
|
|
181
|
+
for (let i = 0; i < MAX_CAUSE_HOPS && cursor; i++) {
|
|
182
|
+
const e = cursor;
|
|
183
|
+
if (typeof e.responseBody === "string" && e.responseBody.trim() !== "")
|
|
184
|
+
return e.responseBody;
|
|
185
|
+
cursor = e.cause;
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
104
189
|
/** Does any link of the `cause` chain look like a transport-level failure? */
|
|
105
190
|
function looksLikeConnectionError(err) {
|
|
106
191
|
let cursor = err;
|
|
@@ -21,11 +21,10 @@ import { type ExecuteAnalysisDeps, type ExecuteAnalysisInput, type ExecuteAnalys
|
|
|
21
21
|
import { type SandboxStepDeps, type SandboxStepInput, type SandboxStepResult } from "../workflows/sandbox-step.js";
|
|
22
22
|
import { type ExecuteTargetAssessmentDeps, type ExecuteTargetAssessmentInput, type ExecuteTargetAssessmentResult } from "../workflows/execute-target-assessment.js";
|
|
23
23
|
import { type DataProfileDeps, type DataProfileWorkflowInput } from "../tasks/data-profile.js";
|
|
24
|
-
import { type EphemeralDeps, type EphemeralResult, type EphemeralWorkflowInput } from "../execution/ephemeral-runner.js";
|
|
25
24
|
/** Registered child sandbox-step callable the parent's child dispatch closes over. */
|
|
26
25
|
export type SandboxStepCallable = (input: SandboxStepInput) => Promise<SandboxStepResult>;
|
|
27
26
|
/**
|
|
28
|
-
* Deps bundles for the
|
|
27
|
+
* Deps bundles for the durable workflows. `executeAnalysis` is a builder
|
|
29
28
|
* because its `sandboxStepCallable` is the registered sandbox-step callable,
|
|
30
29
|
* which does not exist until registration runs inside `assembleCoreRuntime`.
|
|
31
30
|
*/
|
|
@@ -34,7 +33,6 @@ export interface CoreWorkflowDeps {
|
|
|
34
33
|
readonly buildExecuteAnalysis: (sandboxStep: SandboxStepCallable) => ExecuteAnalysisDeps;
|
|
35
34
|
readonly executeTargetAssessment: ExecuteTargetAssessmentDeps;
|
|
36
35
|
readonly dataProfile: DataProfileDeps;
|
|
37
|
-
readonly ephemeral: Omit<EphemeralDeps, "resourcePolicy">;
|
|
38
36
|
}
|
|
39
37
|
/** The registered, callable workflow handles. */
|
|
40
38
|
export interface RegisteredWorkflows {
|
|
@@ -42,22 +40,19 @@ export interface RegisteredWorkflows {
|
|
|
42
40
|
readonly sandboxStep: SandboxStepCallable;
|
|
43
41
|
readonly executeTargetAssessment: (input: ExecuteTargetAssessmentInput) => Promise<ExecuteTargetAssessmentResult>;
|
|
44
42
|
readonly dataProfile: (input: DataProfileWorkflowInput) => Promise<void>;
|
|
45
|
-
readonly ephemeral: (input: EphemeralWorkflowInput) => Promise<EphemeralResult>;
|
|
46
43
|
}
|
|
47
44
|
/**
|
|
48
|
-
* Conversation-agent deps minus the
|
|
45
|
+
* Conversation-agent deps minus the workflow callable and the resource
|
|
49
46
|
* policy — `assembleCoreRuntime` supplies those itself so a caller cannot wire
|
|
50
47
|
* a stale callable or a policy that diverges from the one the workflows see.
|
|
51
48
|
*/
|
|
52
|
-
export type ConversationAssemblyDeps = Omit<ConversationAgentDeps, "executeAnalysisWorkflow" | "
|
|
49
|
+
export type ConversationAssemblyDeps = Omit<ConversationAgentDeps, "executeAnalysisWorkflow" | "resourcePolicy">;
|
|
53
50
|
export interface CoreRuntimeDeps {
|
|
54
51
|
readonly conversation: ConversationAssemblyDeps;
|
|
55
52
|
readonly workflows: CoreWorkflowDeps;
|
|
56
53
|
/**
|
|
57
|
-
* Host resource policy — per-step ceilings
|
|
58
|
-
*
|
|
59
|
-
* `execute_plan` (budget snapshot into workflow input), and the ephemeral
|
|
60
|
-
* runner. Absent, every consumer keeps its legacy behavior.
|
|
54
|
+
* Host resource policy — per-step ceilings and machine budget. One supply
|
|
55
|
+
* point for planner/routing guidance and workflow-input budget snapshots.
|
|
61
56
|
*/
|
|
62
57
|
readonly resourcePolicy?: ResourcePolicy;
|
|
63
58
|
}
|
package/dist/runtime/assemble.js
CHANGED
|
@@ -19,18 +19,15 @@ import { registerExecuteAnalysis } from "../workflows/execute-analysis.js";
|
|
|
19
19
|
import { registerSandboxStep } from "../workflows/sandbox-step.js";
|
|
20
20
|
import { registerExecuteTargetAssessment, } from "../workflows/execute-target-assessment.js";
|
|
21
21
|
import { registerDataProfileWorkflow } from "../tasks/data-profile.js";
|
|
22
|
-
import { registerEphemeralWorkflow } from "../execution/ephemeral-runner.js";
|
|
23
22
|
export function assembleCoreRuntime(deps) {
|
|
24
23
|
const { conversation, workflows: wf, resourcePolicy } = deps;
|
|
25
24
|
const sandboxStep = registerSandboxStep(wf.sandboxStep);
|
|
26
25
|
const executeAnalysis = registerExecuteAnalysis(wf.buildExecuteAnalysis(sandboxStep));
|
|
27
26
|
const executeTargetAssessment = registerExecuteTargetAssessment(wf.executeTargetAssessment);
|
|
28
27
|
const dataProfile = registerDataProfileWorkflow(wf.dataProfile);
|
|
29
|
-
const ephemeral = registerEphemeralWorkflow({ ...wf.ephemeral, resourcePolicy });
|
|
30
28
|
const conversationAgent = createConversationAgent({
|
|
31
29
|
...conversation,
|
|
32
30
|
executeAnalysisWorkflow: executeAnalysis,
|
|
33
|
-
ephemeralWorkflow: ephemeral,
|
|
34
31
|
resourcePolicy,
|
|
35
32
|
});
|
|
36
33
|
return {
|
|
@@ -40,7 +37,6 @@ export function assembleCoreRuntime(deps) {
|
|
|
40
37
|
sandboxStep,
|
|
41
38
|
executeTargetAssessment,
|
|
42
39
|
dataProfile,
|
|
43
|
-
ephemeral,
|
|
44
40
|
},
|
|
45
41
|
};
|
|
46
42
|
}
|
package/dist/runtime/boot.d.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* builds the conversation agent (register-before-launch invariant).
|
|
23
23
|
* 6. `beforeLaunch()` — embedder hook for host-specific pre-launch work that
|
|
24
24
|
* must attach before DBOS launch re-emits events (scheduled sweeps, an
|
|
25
|
-
*
|
|
25
|
+
* legacy-workflow reap, an agent-switch install). Runs after registration
|
|
26
26
|
* so it may close over the registered callables.
|
|
27
27
|
* 7. `launchDbos(...)` — the last registration-dependent step.
|
|
28
28
|
*
|
|
@@ -49,7 +49,7 @@ export interface BootHarnessDeps {
|
|
|
49
49
|
readonly logger: Logger;
|
|
50
50
|
/**
|
|
51
51
|
* Host-specific work that must run AFTER workflow registration and BEFORE
|
|
52
|
-
* DBOS launch (scheduled sweeps,
|
|
52
|
+
* DBOS launch (scheduled sweeps, legacy-row reap, agent-switch install). The
|
|
53
53
|
* booted runtime is not returned until after launch, so this hook captures
|
|
54
54
|
* whatever it needs from the embedder's own composition root.
|
|
55
55
|
*/
|
package/dist/runtime/boot.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* builds the conversation agent (register-before-launch invariant).
|
|
23
23
|
* 6. `beforeLaunch()` — embedder hook for host-specific pre-launch work that
|
|
24
24
|
* must attach before DBOS launch re-emits events (scheduled sweeps, an
|
|
25
|
-
*
|
|
25
|
+
* legacy-workflow reap, an agent-switch install). Runs after registration
|
|
26
26
|
* so it may close over the registered callables.
|
|
27
27
|
* 7. `launchDbos(...)` — the last registration-dependent step.
|
|
28
28
|
*
|
package/dist/runtime/dbos.d.ts
CHANGED
|
@@ -67,11 +67,10 @@ export declare function shutdownDbos({ logger: injected }: {
|
|
|
67
67
|
logger: Logger;
|
|
68
68
|
}): Promise<void>;
|
|
69
69
|
/**
|
|
70
|
-
* Cancel any `ephemeral:`-prefixed PENDING workflow this executor owns
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* awaiter and must never re-execute. DBOS has no "zero recovery" knob, and
|
|
70
|
+
* Cancel any legacy `ephemeral:`-prefixed PENDING workflow this executor owns
|
|
71
|
+
* before `launchDbos`, whose recovery would otherwise re-dispatch rows created
|
|
72
|
+
* by older releases. No current workflow creates this prefix. DBOS has no
|
|
73
|
+
* "zero recovery" knob, and
|
|
75
74
|
* `launch()` starts recovery itself, so there is no post-launch window to
|
|
76
75
|
* cancel from — the only race-free point is a direct system-DB UPDATE before
|
|
77
76
|
* launch. A CANCELLED row is excluded from the recovery query (which selects
|
package/dist/runtime/dbos.js
CHANGED
|
@@ -109,11 +109,10 @@ export async function shutdownDbos({ logger: injected }) {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
-
* Cancel any `ephemeral:`-prefixed PENDING workflow this executor owns
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* awaiter and must never re-execute. DBOS has no "zero recovery" knob, and
|
|
112
|
+
* Cancel any legacy `ephemeral:`-prefixed PENDING workflow this executor owns
|
|
113
|
+
* before `launchDbos`, whose recovery would otherwise re-dispatch rows created
|
|
114
|
+
* by older releases. No current workflow creates this prefix. DBOS has no
|
|
115
|
+
* "zero recovery" knob, and
|
|
117
116
|
* `launch()` starts recovery itself, so there is no post-launch window to
|
|
118
117
|
* cancel from — the only race-free point is a direct system-DB UPDATE before
|
|
119
118
|
* launch. A CANCELLED row is excluded from the recovery query (which selects
|
|
@@ -134,7 +133,7 @@ export async function sweepEphemeralWorkflows({ pool, logger: injectedLogger, ex
|
|
|
134
133
|
values: [Date.now(), executorID],
|
|
135
134
|
});
|
|
136
135
|
if (rowCount && rowCount > 0) {
|
|
137
|
-
logger.info("swept
|
|
136
|
+
logger.info("swept legacy ephemeral workflow rows", { executorID, swept: rowCount });
|
|
138
137
|
}
|
|
139
138
|
}
|
|
140
139
|
catch (err) {
|
|
@@ -142,7 +141,7 @@ export async function sweepEphemeralWorkflows({ pool, logger: injectedLogger, ex
|
|
|
142
141
|
if (err && typeof err === "object" && "code" in err && err.code === "42P01") {
|
|
143
142
|
return;
|
|
144
143
|
}
|
|
145
|
-
logger.error("ephemeral sweep failed", { executorID, ...logger.errorFields(err) });
|
|
144
|
+
logger.error("legacy ephemeral-row sweep failed", { executorID, ...logger.errorFields(err) });
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
/** Snapshot of DBOS lifecycle state — read by the readiness probe. */
|
package/dist/runtime/pools.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-pod Postgres pool sizing — the single source of
|
|
2
|
+
* Per-pod Postgres pool sizing and acquisition bounds — the single source of
|
|
3
|
+
* truth.
|
|
3
4
|
*
|
|
4
5
|
* Cortex runs two pools per pod against the same cluster (see the postgres-storage-backend spec): the
|
|
5
6
|
* application pool (`lib/storage.ts::createPool()`) and the DBOS system-DB
|
|
@@ -21,5 +22,18 @@ export declare const DEFAULT_APP_POOL_SIZE = 12;
|
|
|
21
22
|
* overlap during DBOS recovery, replication / monitoring users.
|
|
22
23
|
*/
|
|
23
24
|
export declare const SAFETY_MARGIN = 5;
|
|
25
|
+
/**
|
|
26
|
+
* How long a caller may wait for a connection from the app pool before the
|
|
27
|
+
* acquisition fails.
|
|
28
|
+
*
|
|
29
|
+
* The driver waits forever by default, which leaves a caller on a saturated
|
|
30
|
+
* pool with no failure mode at all — only an indefinite hang, indistinguishable
|
|
31
|
+
* from work still in progress and therefore able to stall the caller's own
|
|
32
|
+
* in-flight guard permanently. A bound turns that silent stall into a surfaced
|
|
33
|
+
* error the caller can degrade on. 30s is long enough that a healthy pool under
|
|
34
|
+
* burst never trips it, and short enough that a wedged caller surfaces well
|
|
35
|
+
* inside a human's patience.
|
|
36
|
+
*/
|
|
37
|
+
export declare const APP_POOL_ACQUIRE_TIMEOUT_MS = 30000;
|
|
24
38
|
/** Resolve the app pool size from the optional `DB_POOL_MAX` override. */
|
|
25
39
|
export declare function resolveAppPoolSize(dbPoolMax: string | undefined): number;
|
package/dist/runtime/pools.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-pod Postgres pool sizing — the single source of
|
|
2
|
+
* Per-pod Postgres pool sizing and acquisition bounds — the single source of
|
|
3
|
+
* truth.
|
|
3
4
|
*
|
|
4
5
|
* Cortex runs two pools per pod against the same cluster (see the postgres-storage-backend spec): the
|
|
5
6
|
* application pool (`lib/storage.ts::createPool()`) and the DBOS system-DB
|
|
@@ -21,6 +22,19 @@ export const DEFAULT_APP_POOL_SIZE = 12;
|
|
|
21
22
|
* overlap during DBOS recovery, replication / monitoring users.
|
|
22
23
|
*/
|
|
23
24
|
export const SAFETY_MARGIN = 5;
|
|
25
|
+
/**
|
|
26
|
+
* How long a caller may wait for a connection from the app pool before the
|
|
27
|
+
* acquisition fails.
|
|
28
|
+
*
|
|
29
|
+
* The driver waits forever by default, which leaves a caller on a saturated
|
|
30
|
+
* pool with no failure mode at all — only an indefinite hang, indistinguishable
|
|
31
|
+
* from work still in progress and therefore able to stall the caller's own
|
|
32
|
+
* in-flight guard permanently. A bound turns that silent stall into a surfaced
|
|
33
|
+
* error the caller can degrade on. 30s is long enough that a healthy pool under
|
|
34
|
+
* burst never trips it, and short enough that a wedged caller surfaces well
|
|
35
|
+
* inside a human's patience.
|
|
36
|
+
*/
|
|
37
|
+
export const APP_POOL_ACQUIRE_TIMEOUT_MS = 30_000;
|
|
24
38
|
/** Resolve the app pool size from the optional `DB_POOL_MAX` override. */
|
|
25
39
|
export function resolveAppPoolSize(dbPoolMax) {
|
|
26
40
|
if (dbPoolMax === undefined || dbPoolMax === "")
|
|
@@ -24,7 +24,7 @@ export interface MountPlanCoords {
|
|
|
24
24
|
/**
|
|
25
25
|
* Enforced read-only: emit no read-write step mount. The container sees only
|
|
26
26
|
* the read-only analysis tree (plus container-local `/tmp`). Used by the
|
|
27
|
-
*
|
|
27
|
+
* a generic read-only agent that must not mutate analysis files.
|
|
28
28
|
*/
|
|
29
29
|
readOnly?: boolean;
|
|
30
30
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* step and throws directly, so the seam forwards its `Promise<void>` as-is.)
|
|
33
33
|
* Workflow consumers (`sandbox-step.ts`) already wrap each seam call in
|
|
34
34
|
* `DBOS.runStep`, so the re-thrown error records the step as failed;
|
|
35
|
-
* non-workflow consumers (`reaper`, `watchdog`,
|
|
35
|
+
* non-workflow consumers (`reaper`, `watchdog`,
|
|
36
36
|
* `data-profile`, `run-exec`) already handle a thrown failure. They are
|
|
37
37
|
* untouched by this wave.
|
|
38
38
|
*/
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* step and throws directly, so the seam forwards its `Promise<void>` as-is.)
|
|
33
33
|
* Workflow consumers (`sandbox-step.ts`) already wrap each seam call in
|
|
34
34
|
* `DBOS.runStep`, so the re-thrown error records the step as failed;
|
|
35
|
-
* non-workflow consumers (`reaper`, `watchdog`,
|
|
35
|
+
* non-workflow consumers (`reaper`, `watchdog`,
|
|
36
36
|
* `data-profile`, `run-exec`) already handle a thrown failure. They are
|
|
37
37
|
* untouched by this wave.
|
|
38
38
|
*/
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure translation between the agent-loop / sandbox event stream and the
|
|
3
3
|
* typed per-step parts the frontend renders. No DBOS, no per-run state — just the
|
|
4
|
-
* label mapping, the file-tree delta
|
|
5
|
-
*
|
|
4
|
+
* reconciliation-id construction, the label mapping, the file-tree delta
|
|
5
|
+
* extraction/fold, and the chat-data-part narrowing a workflow body composes
|
|
6
|
+
* into its emitters.
|
|
6
7
|
*/
|
|
7
8
|
import type { ChatDataPart, EmitFn } from "../loop/types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Stable reconciliation id for a step's reconciling parts
|
|
11
|
+
* (`data-step-activity`, `data-step-file-tree`). One id per (runId, stepId)
|
|
12
|
+
* so the run-stream fold collapses every phase transition latest-wins onto
|
|
13
|
+
* a single frame. The client keys these by `stepId`, but the server fold
|
|
14
|
+
* keys by part `id`, so the id MUST be unique per step within the run.
|
|
15
|
+
*
|
|
16
|
+
* Every producer of these parts mints its ids here: the id is a
|
|
17
|
+
* reconciliation contract, and the fold collapses correctly only while all
|
|
18
|
+
* producers construct it identically.
|
|
19
|
+
*/
|
|
20
|
+
export declare function stepPartId(kind: string, runId: string, stepId: string): string;
|
|
8
21
|
export declare function activityForTool(name: string, input?: unknown): string;
|
|
9
22
|
/** On-change working-tree delta the sandbox executor posts per exec (paths
|
|
10
23
|
* only; the executor skips directories). */
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure translation between the agent-loop / sandbox event stream and the
|
|
3
3
|
* typed per-step parts the frontend renders. No DBOS, no per-run state — just the
|
|
4
|
-
* label mapping, the file-tree delta
|
|
5
|
-
*
|
|
4
|
+
* reconciliation-id construction, the label mapping, the file-tree delta
|
|
5
|
+
* extraction/fold, and the chat-data-part narrowing a workflow body composes
|
|
6
|
+
* into its emitters.
|
|
6
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* Stable reconciliation id for a step's reconciling parts
|
|
10
|
+
* (`data-step-activity`, `data-step-file-tree`). One id per (runId, stepId)
|
|
11
|
+
* so the run-stream fold collapses every phase transition latest-wins onto
|
|
12
|
+
* a single frame. The client keys these by `stepId`, but the server fold
|
|
13
|
+
* keys by part `id`, so the id MUST be unique per step within the run.
|
|
14
|
+
*
|
|
15
|
+
* Every producer of these parts mints its ids here: the id is a
|
|
16
|
+
* reconciliation contract, and the fold collapses correctly only while all
|
|
17
|
+
* producers construct it identically.
|
|
18
|
+
*/
|
|
19
|
+
export function stepPartId(kind, runId, stepId) {
|
|
20
|
+
return `${kind}-${runId}-${stepId}`;
|
|
21
|
+
}
|
|
7
22
|
/** Friendly live-activity label per sandbox tool id. Falls back to the raw
|
|
8
23
|
* tool name so a newly added tool still reads sensibly. */
|
|
9
24
|
const TOOL_ACTIVITY = {
|
package/dist/sandbox/types.d.ts
CHANGED
|
@@ -241,7 +241,7 @@ export interface CreateSandboxMeta {
|
|
|
241
241
|
* a sandbox with none. */
|
|
242
242
|
resources: ResourceSpec;
|
|
243
243
|
/** Enforced read-only: provision with no read-write step mount, only the
|
|
244
|
-
* read-only analysis tree
|
|
244
|
+
* read-only analysis tree for generic read-only agents. */
|
|
245
245
|
readOnly?: boolean;
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
@@ -22,7 +22,7 @@ export interface ValidatePlanOptions {
|
|
|
22
22
|
* Host per-step resource ceilings. When present, a step whose declared
|
|
23
23
|
* `resources` exceed them is an error — the planner gets actionable
|
|
24
24
|
* feedback at plan time instead of a silent clamp at sandbox creation.
|
|
25
|
-
* The plan-generation path passes this; `
|
|
25
|
+
* The plan-generation path passes this; `execute_analysis` plan mode deliberately does
|
|
26
26
|
* not, so stored plans that predate the policy keep running (the
|
|
27
27
|
* sandbox-creation clamp remains their backstop).
|
|
28
28
|
*/
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
/**
|
|
9
9
|
* A step of an analysis plan. `PlanStepSchema` (schemas/plan-schemas.ts) narrows
|
|
10
|
-
* this into the planner's output contract and emits it as the `
|
|
11
|
-
*
|
|
10
|
+
* this into the planner's output contract and emits it as the `submit_plan`
|
|
11
|
+
* arg schema — so each field's meaning belongs in `.describe()`,
|
|
12
12
|
* not in a comment the model never sees.
|
|
13
13
|
*/
|
|
14
14
|
export declare const AnalysisStepSchema: z.ZodObject<{
|
|
@@ -8,8 +8,8 @@ import { z } from "zod";
|
|
|
8
8
|
// ── Plan structures ─────────────────────────────────────────────────
|
|
9
9
|
/**
|
|
10
10
|
* A step of an analysis plan. `PlanStepSchema` (schemas/plan-schemas.ts) narrows
|
|
11
|
-
* this into the planner's output contract and emits it as the `
|
|
12
|
-
*
|
|
11
|
+
* this into the planner's output contract and emits it as the `submit_plan`
|
|
12
|
+
* arg schema — so each field's meaning belongs in `.describe()`,
|
|
13
13
|
* not in a comment the model never sees.
|
|
14
14
|
*/
|
|
15
15
|
export const AnalysisStepSchema = z.object({
|
|
@@ -101,6 +101,13 @@ export interface DataProfileStatus {
|
|
|
101
101
|
startedAt: string | null;
|
|
102
102
|
completedAt: string | null;
|
|
103
103
|
result: DataProfileResult | null;
|
|
104
|
+
/**
|
|
105
|
+
* The DBOS workflow id of the profile attempt that owns this row — the durable
|
|
106
|
+
* event stream a consumer subscribes to for this profile's activity. `null` means
|
|
107
|
+
* this profile's stream is not addressable (see
|
|
108
|
+
* {@link recordDataProfileWorkflowId}).
|
|
109
|
+
*/
|
|
110
|
+
workflowId: string | null;
|
|
104
111
|
seedInputFileIds: string[] | null;
|
|
105
112
|
}
|
|
106
113
|
/**
|
|
@@ -117,14 +124,59 @@ export interface DataProfileStatus {
|
|
|
117
124
|
* unseeded — neither is an error, both stay in the ok channel.
|
|
118
125
|
*/
|
|
119
126
|
export declare function tryStartDataProfile(pool: Querier, analysisId: string): ResultAsync<boolean, DbError>;
|
|
120
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* Claim a `failed` row back into `running` (the deliberate-retry route). Carries {@link SEEDED}.
|
|
129
|
+
*
|
|
130
|
+
* Clears `data_profile_workflow_id`, because the claim IS the moment a new attempt takes the row
|
|
131
|
+
* and the prior attempt's workflow is finished. Left in place it would leave the row `running`
|
|
132
|
+
* while naming a stream that has already drained, so a consumer would subscribe and observe
|
|
133
|
+
* nothing without knowing why; NULL says "not addressable yet", which is exactly true until the
|
|
134
|
+
* new body records its own id (see {@link recordDataProfileWorkflowId}).
|
|
135
|
+
*/
|
|
121
136
|
export declare function tryRetryDataProfile(pool: Querier, analysisId: string): ResultAsync<boolean, DbError>;
|
|
122
137
|
/**
|
|
123
138
|
* Claim a `completed` row back into `running` (the re-profile route). `data_profile_result`
|
|
124
139
|
* is deliberately preserved so a consumer can keep serving the prior profile while the new
|
|
125
140
|
* one runs. Carries {@link SEEDED}.
|
|
141
|
+
*
|
|
142
|
+
* `data_profile_workflow_id` is NOT preserved alongside it, and the asymmetry is the point: the
|
|
143
|
+
* result is CONTENT that stays valid until replaced, while the id is a POINTER to a live stream
|
|
144
|
+
* whose workflow is now finished. Keeping it would leave the row `running` while naming a drained
|
|
145
|
+
* stream — see {@link tryRetryDataProfile} for the same reasoning.
|
|
126
146
|
*/
|
|
127
147
|
export declare function tryRerunDataProfile(pool: Querier, analysisId: string): ResultAsync<boolean, DbError>;
|
|
148
|
+
/**
|
|
149
|
+
* Record the DBOS workflow id of the attempt that owns a claimed-`running` row, so a
|
|
150
|
+
* consumer resolves which durable event stream carries this profile's activity from the
|
|
151
|
+
* ledger row alone — no durability-engine query, no id reconstructed from the workflow-id
|
|
152
|
+
* string format. The workflow BODY calls this, never the trigger: the claim CAS runs
|
|
153
|
+
* before the workflow id is minted, so only the body can report the id of the attempt
|
|
154
|
+
* that actually started.
|
|
155
|
+
*
|
|
156
|
+
* `AND data_profile_status = 'running'` buys exactly one thing: a write that lands late
|
|
157
|
+
* cannot stamp a row that has already settled, which would otherwise point a consumer at
|
|
158
|
+
* a workflow for a profile that is already finished. What it does NOT buy is
|
|
159
|
+
* disambiguation between two attempts that each believe they are the running one — the
|
|
160
|
+
* stale-expiry claim admits precisely that, since a row whose `data_profile_started_at`
|
|
161
|
+
* has aged past the timeout can be claimed by a second attempt while the first body is
|
|
162
|
+
* still alive but has not completed its first step, and that first step then overwrites
|
|
163
|
+
* the second's id.
|
|
164
|
+
*
|
|
165
|
+
* That residue is deliberately left open rather than closed. Its worst outcome is already
|
|
166
|
+
* a specified-normal state: a consumer subscribed to a superseded workflow reads a stream
|
|
167
|
+
* that has already drained, so it observes no activity — indistinguishable from "running,
|
|
168
|
+
* nothing reported yet". A missing activity line for one profile is acceptable; a wrong
|
|
169
|
+
* one would not be. And closing it costs more than it buys: either the three claim
|
|
170
|
+
* functions widen their `Result<boolean>` returns to carry the id — their callers branch
|
|
171
|
+
* on truthiness (`if (!retried)`), so an object return makes every such branch
|
|
172
|
+
* always-taken, a silent behaviour change in the embedder's recovery path — or the
|
|
173
|
+
* embedder mints the workflow ids, putting a harness-internal construction in a
|
|
174
|
+
* consumer's hands.
|
|
175
|
+
*
|
|
176
|
+
* `ok(true)` when this call stamped the row; `ok(false)` when the CAS refused it — a
|
|
177
|
+
* normal in-band outcome, not an error.
|
|
178
|
+
*/
|
|
179
|
+
export declare function recordDataProfileWorkflowId(pool: Querier, analysisId: string, workflowId: string): ResultAsync<boolean, DbError>;
|
|
128
180
|
/**
|
|
129
181
|
* Stamp a claimed-`running` row `completed` and record its result — a terminal
|
|
130
182
|
* write CAS'd on `data_profile_status = 'running'`.
|