@inflexa-ai/harness 0.39.1 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/dist/agents/conversation-agent.d.ts +3 -0
- package/dist/agents/conversation-agent.js +13 -2
- package/dist/agents/report-session-agent.d.ts +3 -0
- package/dist/agents/report-session-agent.js +2 -0
- package/dist/agents/sandbox/cheminformatics-agent.js +0 -3
- package/dist/agents/sandbox/shared.d.ts +11 -2
- package/dist/agents/sandbox/shared.js +4 -0
- package/dist/app/chat-turn.d.ts +75 -12
- package/dist/app/chat-turn.js +149 -21
- package/dist/app/message-assembly.d.ts +16 -52
- package/dist/app/message-assembly.js +41 -68
- package/dist/app/run-activity.d.ts +4 -6
- package/dist/app/run-activity.js +7 -27
- package/dist/app/spawn-report-session.d.ts +6 -11
- package/dist/app/spawn-report-session.js +5 -6
- package/dist/app/synthesize-run.d.ts +3 -0
- package/dist/app/synthesize-run.js +1 -0
- package/dist/billing/usage-recorder.d.ts +3 -4
- package/dist/billing/usage-recorder.js +3 -4
- package/dist/contracts/chat-parts.d.ts +11 -1
- package/dist/contracts/chat-parts.js +1 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/part-registry.js +1 -0
- package/dist/contracts/report-blocks.d.ts +8 -8
- package/dist/contracts/schemas/chat-parts.d.ts +32 -9
- package/dist/contracts/schemas/chat-parts.js +10 -0
- package/dist/execution/artifact-metadata.d.ts +26 -33
- package/dist/execution/artifact-metadata.js +44 -106
- package/dist/execution/artifact-registration.d.ts +12 -2
- package/dist/execution/artifact-registration.js +9 -4
- package/dist/execution/post-step-pipeline.d.ts +26 -22
- package/dist/execution/post-step-pipeline.js +30 -24
- package/dist/execution/run-synthesis.d.ts +3 -0
- package/dist/execution/run-synthesis.js +11 -1
- package/dist/execution/step-summary.d.ts +21 -30
- package/dist/execution/step-summary.js +30 -57
- package/dist/index.d.ts +11 -10
- package/dist/index.js +16 -35
- package/dist/lib/zod-issues.js +2 -4
- package/dist/loop/compaction.d.ts +20 -0
- package/dist/loop/compaction.js +2 -0
- package/dist/loop/continue-agent.d.ts +40 -0
- package/dist/loop/continue-agent.js +38 -0
- package/dist/loop/metrics.d.ts +30 -22
- package/dist/loop/metrics.js +51 -22
- package/dist/loop/run-agent.d.ts +111 -13
- package/dist/loop/run-agent.js +467 -220
- package/dist/loop/run-to-terminal.d.ts +16 -17
- package/dist/loop/run-to-terminal.js +24 -35
- package/dist/loop/tool-mask.d.ts +23 -0
- package/dist/loop/tool-mask.js +46 -0
- package/dist/loop/tool-output.d.ts +48 -0
- package/dist/loop/tool-output.js +79 -0
- package/dist/loop/types.d.ts +6 -3
- package/dist/memory/ai-sdk-message-storage.d.ts +49 -2
- package/dist/memory/ai-sdk-message-storage.js +78 -2
- package/dist/memory/conversation-display-recorder.d.ts +6 -0
- package/dist/memory/conversation-display-recorder.js +64 -22
- package/dist/memory/conversation-display-replay.d.ts +5 -14
- package/dist/memory/conversation-display-replay.js +66 -32
- package/dist/memory/conversation-display-storage.d.ts +2 -1
- package/dist/memory/conversation-display-storage.js +2 -1
- package/dist/memory/conversation-view.d.ts +53 -0
- package/dist/memory/conversation-view.js +130 -0
- package/dist/memory/count-tokens.d.ts +5 -7
- package/dist/memory/count-tokens.js +7 -9
- package/dist/memory/thread-history.d.ts +74 -102
- package/dist/memory/thread-history.js +181 -246
- package/dist/memory/thread-store.d.ts +3 -3
- package/dist/memory/thread-store.js +7 -2
- package/dist/memory/tool-call-integrity.d.ts +15 -21
- package/dist/memory/tool-call-integrity.js +31 -38
- package/dist/memory/working-memory.d.ts +2 -5
- package/dist/memory/working-memory.js +2 -5
- package/dist/prompts/SOUL.d.ts +2 -2
- package/dist/prompts/SOUL.js +2 -7
- package/dist/prompts/analogical-reasoner.d.ts +1 -1
- package/dist/prompts/analogical-reasoner.js +16 -32
- package/dist/prompts/briefing.js +1 -1
- package/dist/prompts/compaction.d.ts +4 -0
- package/dist/prompts/compaction.js +24 -0
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +26 -35
- package/dist/prompts/execute-analysis/step-summary.js +7 -5
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +29 -34
- package/dist/prompts/planner.js +15 -29
- package/dist/prompts/report-session.d.ts +1 -1
- package/dist/prompts/report-session.js +2 -33
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +1 -2
- package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/cheminformatics-agent.js +10 -29
- package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
- package/dist/prompts/sandbox/chromatin-agent.js +1 -2
- package/dist/prompts/sandbox/data-profiler.js +6 -3
- package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
- package/dist/prompts/sandbox/dna-methylation-agent.js +2 -7
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +20 -24
- package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
- package/dist/prompts/sandbox/enrichment-agent.js +3 -2
- package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
- package/dist/prompts/sandbox/genomic-variant-agent.js +0 -2
- package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/immune-profiling-agent.js +7 -14
- package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/metabolomics-agent.js +0 -2
- package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
- package/dist/prompts/sandbox/microbiome-agent.js +14 -21
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +9 -19
- package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multimodal-sc-agent.js +4 -5
- package/dist/prompts/sandbox/network-agent.d.ts +1 -1
- package/dist/prompts/sandbox/network-agent.js +7 -8
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +19 -19
- package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/proteomics-agent.js +3 -4
- package/dist/prompts/sandbox/scientific-executor.d.ts +1 -1
- package/dist/prompts/sandbox/scientific-executor.js +7 -10
- package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
- package/dist/prompts/sandbox/single-cell-agent.js +2 -4
- package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/spatial-omics-agent.js +3 -5
- package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/statistical-modeling-agent.js +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.js +10 -19
- package/dist/prompts/sandbox-standards.d.ts +7 -7
- package/dist/prompts/sandbox-standards.js +74 -76
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +16 -42
- package/dist/providers/ai-sdk.d.ts +39 -6
- package/dist/providers/ai-sdk.js +117 -18
- package/dist/providers/errors.d.ts +2 -0
- package/dist/providers/errors.js +5 -0
- package/dist/providers/prompt-cache.d.ts +43 -41
- package/dist/providers/prompt-cache.js +47 -41
- package/dist/providers/reasoning.d.ts +10 -21
- package/dist/providers/reasoning.js +10 -21
- package/dist/providers/types.d.ts +21 -5
- package/dist/report-model/authoring-grammar.d.ts +2 -2
- package/dist/report-model/pin-snapshot.js +4 -10
- package/dist/runtime/assemble.d.ts +9 -7
- package/dist/runtime/assemble.js +7 -3
- package/dist/sandbox/create-sandbox.d.ts +2 -2
- package/dist/sandbox/submit-exec.d.ts +1 -1
- package/dist/schemas/artifact-manifest.d.ts +4 -4
- package/dist/state/artifacts.d.ts +11 -9
- package/dist/state/artifacts.js +112 -93
- package/dist/state/data-profile.d.ts +2 -2
- package/dist/state/data-profile.js +2 -2
- package/dist/state/init.js +39 -4
- package/dist/state/purge-analysis.js +4 -0
- package/dist/state/tool-outputs.d.ts +4 -0
- package/dist/state/tool-outputs.js +30 -0
- package/dist/tasks/data-profile.d.ts +31 -10
- package/dist/tasks/data-profile.js +116 -95
- package/dist/tools/ad-hoc-router.d.ts +8 -0
- package/dist/tools/ad-hoc-router.js +21 -2
- package/dist/tools/display/show-user.d.ts +1 -1
- package/dist/tools/execute-analysis.d.ts +3 -0
- package/dist/tools/execute-analysis.js +9 -1
- package/dist/tools/read-tool-output.d.ts +7 -0
- package/dist/tools/read-tool-output.js +130 -0
- package/dist/tools/research/generate-analogy-report.d.ts +10 -26
- package/dist/tools/research/generate-analogy-report.js +76 -163
- package/dist/tools/research/generate-plan.d.ts +3 -0
- package/dist/tools/research/generate-plan.js +4 -1
- package/dist/tools/research/literature-reviewer.d.ts +3 -0
- package/dist/tools/research/literature-reviewer.js +3 -0
- package/dist/tools/sandbox/report-blocker.d.ts +18 -5
- package/dist/tools/sandbox/report-blocker.js +54 -6
- package/dist/tools/sandbox/submit-file-metadata.d.ts +30 -0
- package/dist/tools/sandbox/submit-file-metadata.js +67 -0
- package/dist/tools/start-report-session.d.ts +1 -3
- package/dist/tools/start-report-session.js +0 -2
- package/dist/tools/workspace/execute-command.js +7 -4
- package/dist/tools/workspace/result-bounds.d.ts +4 -4
- package/dist/tools/workspace/result-bounds.js +6 -5
- package/dist/tools/workspace/workspace-search.d.ts +1 -1
- package/dist/workflows/execute-analysis.d.ts +3 -0
- package/dist/workflows/execute-analysis.js +6 -3
- package/dist/workflows/sandbox-step.d.ts +30 -9
- package/dist/workflows/sandbox-step.js +37 -8
- package/package.json +9 -9
- package/dist/providers/anthropic.d.ts +0 -25
- package/dist/providers/anthropic.js +0 -28
|
@@ -1,34 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The reasoning depth of a
|
|
2
|
+
* The reasoning depth of a call.
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* The effort resolves in order: `ChatRequest.reasoning` (set only through
|
|
5
|
+
* `RunAgentOptions.reasoning`), the provider configuration's `reasoning`, then
|
|
6
|
+
* {@link DEFAULT_REASONING}. Anthropic discards its message cache when the
|
|
7
|
+
* top-level effort changes between calls.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* The harness wrote `providerOptions.anthropic.effort` before. A value on that
|
|
12
|
-
* key turns the per-model table of the Anthropic package off, thus the raw name
|
|
13
|
-
* reached the wire. A model that accepts `high` but not `xhigh` answered 400.
|
|
14
|
-
* The neutral field has no such hazard, because the package resolves the name
|
|
15
|
-
* for the model that it is bound to.
|
|
16
|
-
*
|
|
17
|
-
* ## Where the policy belongs
|
|
18
|
-
*
|
|
19
|
-
* The policy rides on the run, not on the provider, for the same reason that the
|
|
20
|
-
* cache policy does. A one-shot LLM call elsewhere in the harness has its own
|
|
21
|
-
* depth needs, and it must not inherit the depth of an agent loop.
|
|
9
|
+
* Do not set `providerOptions.anthropic.effort` directly. It bypasses the
|
|
10
|
+
* per-model table, and a model that rejects the raw name answers 400.
|
|
22
11
|
*/
|
|
23
12
|
/**
|
|
24
|
-
* The
|
|
13
|
+
* The last source of the effort: the deepest rung of the neutral ladder.
|
|
25
14
|
*
|
|
26
15
|
* Each agent of the harness drives tools over many iterations. A shallow turn
|
|
27
16
|
* there wastes more calls than a deeper turn costs in tokens. The Anthropic
|
|
28
17
|
* package sends `xhigh` to a model that accepts it, and `max` to a model that
|
|
29
18
|
* does not. The OpenAI-compatible package sends the name as it is.
|
|
30
19
|
*
|
|
31
|
-
* A host that wants a cheaper
|
|
32
|
-
* no reasoning support
|
|
20
|
+
* A host that wants a cheaper role sets a lower name on that role's provider
|
|
21
|
+
* configuration. With no reasoning support, a host sets `"provider-default"`.
|
|
33
22
|
*/
|
|
34
23
|
export const DEFAULT_REASONING = "xhigh";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* vendor-neutral interfaces. Every call carries an `AgentSession`; billing
|
|
6
6
|
* attribution is resolved lazily at the provider wire boundary.
|
|
7
7
|
*/
|
|
8
|
-
import type { FinishReason, LanguageModel, ModelMessage, ToolSet } from "ai";
|
|
8
|
+
import type { FinishReason, LanguageModel, ModelMessage, SystemModelMessage, ToolSet } from "ai";
|
|
9
9
|
import type { LanguageModelV4CallOptions } from "@ai-sdk/provider";
|
|
10
10
|
import type { ProviderOptions } from "@ai-sdk/provider-utils";
|
|
11
11
|
import type { ResultAsync } from "neverthrow";
|
|
@@ -32,19 +32,30 @@ export interface ProviderCapabilities {
|
|
|
32
32
|
*/
|
|
33
33
|
readonly imageUserMessages?: boolean;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* The request carries no free-form provider options. That would let a caller
|
|
37
|
+
* set a vendor key that bypasses the provider's per-model table.
|
|
38
|
+
*/
|
|
35
39
|
export interface ChatRequest {
|
|
36
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The system prompt: a plain string, or a system message that carries the
|
|
42
|
+
* cache marker at its end (`withSystemPromptBreakpoint`).
|
|
43
|
+
*/
|
|
44
|
+
readonly system: string | SystemModelMessage;
|
|
37
45
|
readonly messages: readonly ModelMessage[];
|
|
38
46
|
readonly tools: ToolSet;
|
|
39
47
|
/**
|
|
40
48
|
* A forced choice (`required`, or one named tool) is absent on purpose: some
|
|
41
49
|
* Claude models reject it with a 400, and the model is chosen at run time.
|
|
50
|
+
*
|
|
51
|
+
* CAUTION: `@ai-sdk/anthropic` strips the tools when this is `"none"`, and
|
|
52
|
+
* Anthropic drops its cache on any `tool_choice` change — taking a signed
|
|
53
|
+
* thinking block with it. Use a tool mask instead of sending `"none"`.
|
|
42
54
|
*/
|
|
43
55
|
readonly toolChoice?: "auto" | "none";
|
|
44
|
-
readonly providerOptions?: ProviderOptions;
|
|
45
56
|
/**
|
|
46
|
-
* How deep the model reasons
|
|
47
|
-
*
|
|
57
|
+
* How deep the model reasons. Absent, the effort falls back to the provider
|
|
58
|
+
* configuration's `reasoning`, then `DEFAULT_REASONING`.
|
|
48
59
|
*/
|
|
49
60
|
readonly reasoning?: ReasoningPolicy;
|
|
50
61
|
}
|
|
@@ -139,6 +150,11 @@ export interface ChatResponse {
|
|
|
139
150
|
* diagnostics, never as an invariant.
|
|
140
151
|
*/
|
|
141
152
|
readonly servedModelId?: string;
|
|
153
|
+
/**
|
|
154
|
+
* The AI SDK's `LanguageModel.provider` id, for example `anthropic.messages`.
|
|
155
|
+
* Absent for a bare model-id string, which names no provider.
|
|
156
|
+
*/
|
|
157
|
+
readonly provider?: string;
|
|
142
158
|
}
|
|
143
159
|
export type ChatStreamEvent = {
|
|
144
160
|
readonly type: "text-delta";
|
|
@@ -398,15 +398,15 @@ declare const AUTHORING_ATOM_SCHEMAS: readonly [z.ZodObject<{
|
|
|
398
398
|
x: z.ZodOptional<z.ZodObject<{
|
|
399
399
|
title: z.ZodOptional<z.ZodString>;
|
|
400
400
|
scale: z.ZodOptional<z.ZodEnum<{
|
|
401
|
-
linear: "linear";
|
|
402
401
|
log: "log";
|
|
402
|
+
linear: "linear";
|
|
403
403
|
}>>;
|
|
404
404
|
}, z.core.$strict>>;
|
|
405
405
|
y: z.ZodOptional<z.ZodObject<{
|
|
406
406
|
title: z.ZodOptional<z.ZodString>;
|
|
407
407
|
scale: z.ZodOptional<z.ZodEnum<{
|
|
408
|
-
linear: "linear";
|
|
409
408
|
log: "log";
|
|
409
|
+
linear: "linear";
|
|
410
410
|
}>>;
|
|
411
411
|
}, z.core.$strict>>;
|
|
412
412
|
}, z.core.$strict>>;
|
|
@@ -210,19 +210,13 @@ async function collectCitations(pool, resolveWorkspaceRoot, analysisId) {
|
|
|
210
210
|
* tier, which runs one time for each report version.
|
|
211
211
|
*/
|
|
212
212
|
export async function pinReportSnapshot(pool, analysisId, options = {}) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
catch (cause) {
|
|
218
|
-
// The query speaks the throw protocol of the `pg` driver. This is the thin wrapper that turns
|
|
219
|
-
// that throw into a value, thus each caller above reads a failure as data.
|
|
220
|
-
return err({ kind: "ledger-read-failed", cause });
|
|
221
|
-
}
|
|
213
|
+
const ledgerRows = await queryAnalysisArtifacts(pool, analysisId);
|
|
214
|
+
if (ledgerRows.isErr())
|
|
215
|
+
return err({ kind: "ledger-read-failed", cause: ledgerRows.error.cause });
|
|
222
216
|
// The ledger accepts any path. A null-prototype map keeps a key such as `__proto__` an ordinary
|
|
223
217
|
// entry, thus no path collides with a prototype slot.
|
|
224
218
|
const artifacts = Object.create(null);
|
|
225
|
-
for (const row of ledgerRows) {
|
|
219
|
+
for (const row of ledgerRows.value) {
|
|
226
220
|
artifacts[row.path] = { hash: row.hash, fileType: row.fileType };
|
|
227
221
|
}
|
|
228
222
|
// A citation reference resolves against this list: the resolver refuses a key that the list does not
|
|
@@ -49,12 +49,13 @@ export type SandboxStepCallable = (input: SandboxStepInput) => Promise<SandboxSt
|
|
|
49
49
|
* here would let an embedder wire a recorder the workflows use and the
|
|
50
50
|
* conversation agent does not — a half-wired ledger that reads as a complete
|
|
51
51
|
* one. The protection has to hold on both sides of the assembly, not just the
|
|
52
|
-
* conversation side.
|
|
52
|
+
* conversation side. Each bag omits `toolOutputStore` for the same reason: each
|
|
53
|
+
* loop must keep its texts in the one store that each read tool reads.
|
|
53
54
|
*/
|
|
54
55
|
export interface CoreWorkflowDeps {
|
|
55
|
-
readonly sandboxStep: Omit<SandboxStepDeps, "usageRecorder" | "citationResolver">;
|
|
56
|
-
readonly buildExecuteAnalysis: (sandboxStep: SandboxStepCallable) => Omit<ExecuteAnalysisDeps, "usageRecorder" | "citationResolver">;
|
|
57
|
-
readonly dataProfile: Omit<DataProfileDeps, "usageRecorder">;
|
|
56
|
+
readonly sandboxStep: Omit<SandboxStepDeps, "usageRecorder" | "citationResolver" | "toolOutputStore">;
|
|
57
|
+
readonly buildExecuteAnalysis: (sandboxStep: SandboxStepCallable) => Omit<ExecuteAnalysisDeps, "usageRecorder" | "citationResolver" | "toolOutputStore">;
|
|
58
|
+
readonly dataProfile: Omit<DataProfileDeps, "usageRecorder" | "toolOutputStore">;
|
|
58
59
|
}
|
|
59
60
|
/** The registered, callable workflow handles. */
|
|
60
61
|
export interface RegisteredWorkflows {
|
|
@@ -66,21 +67,22 @@ export interface RegisteredWorkflows {
|
|
|
66
67
|
}
|
|
67
68
|
/**
|
|
68
69
|
* Conversation-agent deps minus the workflow callable, the resource policy, the
|
|
69
|
-
* usage recorder, the report-session anchor, and the
|
|
70
|
+
* usage recorder, the report-session anchor, the eyes, and the tool output store.
|
|
70
71
|
* `assembleCoreRuntime` supplies each of those itself. Thus a caller cannot wire
|
|
71
|
-
* one of these
|
|
72
|
+
* one of these six values:
|
|
72
73
|
*
|
|
73
74
|
* - a stale callable
|
|
74
75
|
* - a policy that diverges from the one the workflows see
|
|
75
76
|
* - a recorder that only half the agent tree reports to
|
|
76
77
|
* - an anchor over a different session runtime
|
|
77
78
|
* - a seam that only half the agent tree looks through
|
|
79
|
+
* - a store that only half the agent tree keeps its texts in
|
|
78
80
|
*
|
|
79
81
|
* The assembly resolves the eyes one time, from `CoreRuntimeDeps.eyes` and the
|
|
80
82
|
* chrome config. A caller that bound the eyes here would give the conversation
|
|
81
83
|
* agent a seam that the report agent never sees.
|
|
82
84
|
*/
|
|
83
|
-
export type ConversationAssemblyDeps = Omit<ConversationAgentDeps, "executeAnalysisWorkflow" | "resourcePolicy" | "usageRecorder" | "citationResolver" | "anchorReportSession" | "eyes">;
|
|
85
|
+
export type ConversationAssemblyDeps = Omit<ConversationAgentDeps, "executeAnalysisWorkflow" | "resourcePolicy" | "usageRecorder" | "citationResolver" | "anchorReportSession" | "eyes" | "toolOutputStore">;
|
|
84
86
|
/**
|
|
85
87
|
* What binds one reference resolver: the analysis whose pinned artifacts it reads, and the auth of the tool
|
|
86
88
|
* call that reads them. A resolver serves one analysis, thus the report tools build one for each call.
|
package/dist/runtime/assemble.js
CHANGED
|
@@ -30,6 +30,7 @@ import { createCitationResolver } from "../citations/resolve.js";
|
|
|
30
30
|
import { createThreadStore } from "../memory/thread-store.js";
|
|
31
31
|
import { createArtifactReadStore, createProductionResolver } from "../report-model/production-resolver.js";
|
|
32
32
|
import { createReportVersionStore } from "../state/report-versions.js";
|
|
33
|
+
import { createToolOutputStore } from "../state/tool-outputs.js";
|
|
33
34
|
const _assertDomainError = true;
|
|
34
35
|
/**
|
|
35
36
|
* Wrap a type→agent registry as the resolution surface. Held apart from
|
|
@@ -83,9 +84,10 @@ export function assembleCoreRuntime(deps) {
|
|
|
83
84
|
? {}
|
|
84
85
|
: { semanticScholarApiKey: conversation.bioKeys.semanticScholar }),
|
|
85
86
|
});
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
87
|
+
const toolOutputStore = createToolOutputStore(conversation.pool);
|
|
88
|
+
const sandboxStep = registerSandboxStep({ ...wf.sandboxStep, citationResolver, usageRecorder, toolOutputStore });
|
|
89
|
+
const executeAnalysis = registerExecuteAnalysis({ ...wf.buildExecuteAnalysis(sandboxStep), citationResolver, usageRecorder, toolOutputStore });
|
|
90
|
+
const dataProfile = registerDataProfileWorkflow({ ...wf.dataProfile, usageRecorder, toolOutputStore });
|
|
89
91
|
// The extraction workflow shares the profile's sandbox and authorization rails, thus it draws the same
|
|
90
92
|
// three seams from the profile deps. The report resolver factory binds the extraction arm over this
|
|
91
93
|
// callable, thus a fall-through report reference reads its file out of process on the profile rails.
|
|
@@ -120,6 +122,7 @@ export function assembleCoreRuntime(deps) {
|
|
|
120
122
|
anchorReportSession: reportSession.ensureSessionState,
|
|
121
123
|
resourcePolicy,
|
|
122
124
|
usageRecorder,
|
|
125
|
+
toolOutputStore,
|
|
123
126
|
citationResolver,
|
|
124
127
|
...(eyes ? { eyes } : {}),
|
|
125
128
|
// The start tool passes it to the spawn, which emits the creation of a
|
|
@@ -176,6 +179,7 @@ export function assembleCoreRuntime(deps) {
|
|
|
176
179
|
...(deps.resolveReportPageUrl ? { resolvePageUrl: deps.resolveReportPageUrl } : {}),
|
|
177
180
|
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
178
181
|
...(conversation.logger ? { logger: conversation.logger } : {}),
|
|
182
|
+
toolOutputStore,
|
|
179
183
|
});
|
|
180
184
|
// The single registration point for every typed agent. A future thread type's
|
|
181
185
|
// agent plugs in here at assembly with no embedder change. `conversation` is
|
|
@@ -49,8 +49,8 @@ export interface CreateSandboxClientConfig {
|
|
|
49
49
|
/**
|
|
50
50
|
* Per-stream retention budget sent with every exec, so the sandbox drops
|
|
51
51
|
* output past it instead of shipping it. Defaults to `EXEC_STREAM_BYTE_CAP`,
|
|
52
|
-
* the
|
|
53
|
-
* host will keep buys nothing.
|
|
52
|
+
* the maximum of a kept tool output and the same value the host truncates to
|
|
53
|
+
* on receipt — sending more than the host will keep buys nothing.
|
|
54
54
|
*/
|
|
55
55
|
execStreamByteCap?: number;
|
|
56
56
|
/** Cluster resource ceilings; every sandbox request is clamped to these. */
|
|
@@ -26,7 +26,7 @@ export interface SubmitExecDeps {
|
|
|
26
26
|
}) => Promise<T>;
|
|
27
27
|
/**
|
|
28
28
|
* Per-stream retention budget to send when the body does not carry one.
|
|
29
|
-
* Defaults to `EXEC_STREAM_BYTE_CAP
|
|
29
|
+
* Defaults to `EXEC_STREAM_BYTE_CAP`, the maximum of a kept tool output.
|
|
30
30
|
*/
|
|
31
31
|
execStreamByteCap?: number;
|
|
32
32
|
}
|
|
@@ -8,9 +8,9 @@ import { z } from "zod";
|
|
|
8
8
|
/** Artifact type inferred from the step subdirectory. */
|
|
9
9
|
export declare const ArtifactTypeSchema: z.ZodEnum<{
|
|
10
10
|
output: "output";
|
|
11
|
-
log: "log";
|
|
12
|
-
figure: "figure";
|
|
13
11
|
script: "script";
|
|
12
|
+
figure: "figure";
|
|
13
|
+
log: "log";
|
|
14
14
|
notebook: "notebook";
|
|
15
15
|
}>;
|
|
16
16
|
export type ArtifactType = z.infer<typeof ArtifactTypeSchema>;
|
|
@@ -22,9 +22,9 @@ export declare const ArtifactManifestEntrySchema: z.ZodObject<{
|
|
|
22
22
|
size: z.ZodNumber;
|
|
23
23
|
type: z.ZodEnum<{
|
|
24
24
|
output: "output";
|
|
25
|
-
log: "log";
|
|
26
|
-
figure: "figure";
|
|
27
25
|
script: "script";
|
|
26
|
+
figure: "figure";
|
|
27
|
+
log: "log";
|
|
28
28
|
notebook: "notebook";
|
|
29
29
|
}>;
|
|
30
30
|
hash: z.ZodOptional<z.ZodString>;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* `cortex_artifacts` operations — artifact upsert, lookup, and file-id
|
|
3
3
|
* reconciliation.
|
|
4
4
|
*/
|
|
5
|
+
import type { ResultAsync } from "neverthrow";
|
|
6
|
+
import { type DbError } from "../lib/db-result.js";
|
|
5
7
|
import type { Querier } from "./db.js";
|
|
6
8
|
import type { ArtifactRow } from "./schema.js";
|
|
7
9
|
export interface RegisterArtifactInput {
|
|
@@ -20,7 +22,7 @@ export interface RegisterArtifactInput {
|
|
|
20
22
|
*/
|
|
21
23
|
fileId?: string | null;
|
|
22
24
|
}
|
|
23
|
-
export declare function upsertArtifact(pool: Querier, entry: RegisterArtifactInput):
|
|
25
|
+
export declare function upsertArtifact(pool: Querier, entry: RegisterArtifactInput): ResultAsync<void, DbError>;
|
|
24
26
|
/**
|
|
25
27
|
* Batched upsert — writes entries in multi-row `INSERT ... VALUES` statements
|
|
26
28
|
* of at most {@link ROWS_PER_STATEMENT} rows. Callers range from per-step
|
|
@@ -30,7 +32,7 @@ export declare function upsertArtifact(pool: Querier, entry: RegisterArtifactInp
|
|
|
30
32
|
* idempotent per row (`ON CONFLICT ... DO UPDATE`), so a failure between
|
|
31
33
|
* chunks is healed by the caller's retry re-upserting the same manifest.
|
|
32
34
|
*/
|
|
33
|
-
export declare function upsertArtifacts(pool: Querier, entries: RegisterArtifactInput[]):
|
|
35
|
+
export declare function upsertArtifacts(pool: Querier, entries: RegisterArtifactInput[]): ResultAsync<void, DbError>;
|
|
34
36
|
/** Result type for input artifact metadata lookups. */
|
|
35
37
|
export interface InputArtifactMeta {
|
|
36
38
|
path: string;
|
|
@@ -42,8 +44,8 @@ export interface InputArtifactMeta {
|
|
|
42
44
|
* Query cortex_artifacts for input-role rows matching the given paths.
|
|
43
45
|
* Used at the registration boundary to resolve metadata for data-source inputs.
|
|
44
46
|
*/
|
|
45
|
-
export declare function queryInputArtifacts(pool: Querier, analysisId: string, paths: string[]):
|
|
46
|
-
export declare function queryUnsyncedStepArtifacts(pool: Querier, resourceId: string, runId: string, stepId: string):
|
|
47
|
+
export declare function queryInputArtifacts(pool: Querier, analysisId: string, paths: string[]): ResultAsync<InputArtifactMeta[], DbError>;
|
|
48
|
+
export declare function queryUnsyncedStepArtifacts(pool: Querier, resourceId: string, runId: string, stepId: string): ResultAsync<ArtifactRow[], DbError>;
|
|
47
49
|
/** One registered step output, as a downstream consumer needs to name it. */
|
|
48
50
|
export interface StepArtifactRef {
|
|
49
51
|
/** Workspace-root-relative path (`runs/{runId}/{stepId}/output/de.csv`). */
|
|
@@ -56,7 +58,7 @@ export interface StepArtifactRef {
|
|
|
56
58
|
* path, so a `limit` truncates the tail of the list rather than an arbitrary
|
|
57
59
|
* slice of it — and so the same call replays to the same rows.
|
|
58
60
|
*/
|
|
59
|
-
export declare function queryStepArtifactPaths(pool: Querier, resourceId: string, runId: string, stepId: string, limit: number):
|
|
61
|
+
export declare function queryStepArtifactPaths(pool: Querier, resourceId: string, runId: string, stepId: string, limit: number): ResultAsync<StepArtifactRef[], DbError>;
|
|
60
62
|
/** One registered artifact of an analysis, as a reader of the full artifact set names it. */
|
|
61
63
|
export interface AnalysisArtifactRef {
|
|
62
64
|
/** Workspace-root-relative path (`runs/{runId}/{stepId}/output/de.csv`). */
|
|
@@ -72,11 +74,11 @@ export interface AnalysisArtifactRef {
|
|
|
72
74
|
* query drops such a row, a later refusal says that the artifact never existed, and that reason is
|
|
73
75
|
* false.
|
|
74
76
|
*/
|
|
75
|
-
export declare function queryAnalysisArtifacts(pool: Querier, analysisId: string):
|
|
77
|
+
export declare function queryAnalysisArtifacts(pool: Querier, analysisId: string): ResultAsync<AnalysisArtifactRef[], DbError>;
|
|
76
78
|
/** Count step-output artifacts produced by a run — for the run-completed card. */
|
|
77
|
-
export declare function countArtifactsForRun(pool: Querier, analysisId: string, runId: string):
|
|
78
|
-
export declare function updateArtifactId(pool: Querier, resourceId: string, path: string, artifactId: string, fileType?: string | null):
|
|
79
|
+
export declare function countArtifactsForRun(pool: Querier, analysisId: string, runId: string): ResultAsync<number, DbError>;
|
|
80
|
+
export declare function updateArtifactId(pool: Querier, resourceId: string, path: string, artifactId: string, fileType?: string | null): ResultAsync<void, DbError>;
|
|
79
81
|
export declare function updateFileIds(pool: Querier, pairs: Array<{
|
|
80
82
|
artifactId: string;
|
|
81
83
|
fileId: string;
|
|
82
|
-
}>):
|
|
84
|
+
}>): ResultAsync<void, DbError>;
|
package/dist/state/artifacts.js
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
* `cortex_artifacts` operations — artifact upsert, lookup, and file-id
|
|
3
3
|
* reconciliation.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import { tryMutation, tryQuery } from "../lib/db-result.js";
|
|
6
|
+
export function upsertArtifact(pool, entry) {
|
|
6
7
|
const now = new Date().toISOString();
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
return tryMutation("artifacts.upsertArtifact", async () => {
|
|
9
|
+
await pool.query({
|
|
10
|
+
text: `INSERT INTO cortex_artifacts
|
|
9
11
|
(analysis_id, path, hash, size, role, source_step, source_run, file_type, file_id, created_at)
|
|
10
12
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
11
13
|
ON CONFLICT (analysis_id, path) DO UPDATE SET
|
|
@@ -16,18 +18,19 @@ export async function upsertArtifact(pool, entry) {
|
|
|
16
18
|
source_run = EXCLUDED.source_run,
|
|
17
19
|
file_type = COALESCE(EXCLUDED.file_type, cortex_artifacts.file_type),
|
|
18
20
|
file_id = COALESCE(EXCLUDED.file_id, cortex_artifacts.file_id)`,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
values: [
|
|
22
|
+
entry.resourceId,
|
|
23
|
+
entry.path,
|
|
24
|
+
entry.hash,
|
|
25
|
+
entry.size,
|
|
26
|
+
entry.role,
|
|
27
|
+
entry.sourceStep ?? null,
|
|
28
|
+
entry.sourceRun ?? null,
|
|
29
|
+
entry.fileType ?? null,
|
|
30
|
+
entry.fileId ?? null,
|
|
31
|
+
now,
|
|
32
|
+
],
|
|
33
|
+
});
|
|
31
34
|
});
|
|
32
35
|
}
|
|
33
36
|
const COLS_PER_ROW = 10;
|
|
@@ -49,31 +52,32 @@ const ROWS_PER_STATEMENT = 1_000;
|
|
|
49
52
|
* idempotent per row (`ON CONFLICT ... DO UPDATE`), so a failure between
|
|
50
53
|
* chunks is healed by the caller's retry re-upserting the same manifest.
|
|
51
54
|
*/
|
|
52
|
-
export
|
|
55
|
+
export function upsertArtifacts(pool, entries) {
|
|
53
56
|
const now = new Date().toISOString();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
e
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
57
|
+
return tryMutation("artifacts.upsertArtifacts", async () => {
|
|
58
|
+
for (let start = 0; start < entries.length; start += ROWS_PER_STATEMENT) {
|
|
59
|
+
const chunk = entries.slice(start, start + ROWS_PER_STATEMENT);
|
|
60
|
+
const placeholders = chunk
|
|
61
|
+
.map((_, i) => {
|
|
62
|
+
const base = i * COLS_PER_ROW;
|
|
63
|
+
return (`($${base + 1}, $${base + 2}, $${base + 3}, $${base + 4}, ` +
|
|
64
|
+
`$${base + 5}, $${base + 6}, $${base + 7}, $${base + 8}, $${base + 9}, $${base + 10})`);
|
|
65
|
+
})
|
|
66
|
+
.join(", ");
|
|
67
|
+
const values = chunk.flatMap((e) => [
|
|
68
|
+
e.resourceId,
|
|
69
|
+
e.path,
|
|
70
|
+
e.hash,
|
|
71
|
+
e.size,
|
|
72
|
+
e.role,
|
|
73
|
+
e.sourceStep ?? null,
|
|
74
|
+
e.sourceRun ?? null,
|
|
75
|
+
e.fileType ?? null,
|
|
76
|
+
e.fileId ?? null,
|
|
77
|
+
now,
|
|
78
|
+
]);
|
|
79
|
+
await pool.query({
|
|
80
|
+
text: `INSERT INTO cortex_artifacts
|
|
77
81
|
(analysis_id, path, hash, size, role, source_step, source_run, file_type, file_id, created_at)
|
|
78
82
|
VALUES ${placeholders}
|
|
79
83
|
ON CONFLICT (analysis_id, path) DO UPDATE SET
|
|
@@ -84,42 +88,47 @@ export async function upsertArtifacts(pool, entries) {
|
|
|
84
88
|
source_run = EXCLUDED.source_run,
|
|
85
89
|
file_type = COALESCE(EXCLUDED.file_type, cortex_artifacts.file_type),
|
|
86
90
|
file_id = COALESCE(EXCLUDED.file_id, cortex_artifacts.file_id)`,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
values,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
90
95
|
}
|
|
91
96
|
/**
|
|
92
97
|
* Query cortex_artifacts for input-role rows matching the given paths.
|
|
93
98
|
* Used at the registration boundary to resolve metadata for data-source inputs.
|
|
94
99
|
*/
|
|
95
|
-
export
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
export function queryInputArtifacts(pool, analysisId, paths) {
|
|
101
|
+
return tryQuery("artifacts.queryInputArtifacts", async () => {
|
|
102
|
+
if (paths.length === 0)
|
|
103
|
+
return [];
|
|
104
|
+
const result = await pool.query({
|
|
105
|
+
text: `SELECT path, hash, size, file_id
|
|
100
106
|
FROM cortex_artifacts
|
|
101
107
|
WHERE analysis_id = $1 AND role = 'input' AND path = ANY($2::text[])`,
|
|
102
|
-
|
|
108
|
+
values: [analysisId, paths],
|
|
109
|
+
});
|
|
110
|
+
return result.rows.map((r) => ({
|
|
111
|
+
path: r.path,
|
|
112
|
+
hash: r.hash,
|
|
113
|
+
size: Number(r.size),
|
|
114
|
+
fileId: r.file_id ?? null,
|
|
115
|
+
}));
|
|
103
116
|
});
|
|
104
|
-
return result.rows.map((r) => ({
|
|
105
|
-
path: r.path,
|
|
106
|
-
hash: r.hash,
|
|
107
|
-
size: Number(r.size),
|
|
108
|
-
fileId: r.file_id ?? null,
|
|
109
|
-
}));
|
|
110
117
|
}
|
|
111
|
-
export
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
export function queryUnsyncedStepArtifacts(pool, resourceId, runId, stepId) {
|
|
119
|
+
return tryQuery("artifacts.queryUnsyncedStepArtifacts", async () => {
|
|
120
|
+
const result = await pool.query({
|
|
121
|
+
text: `SELECT analysis_id, path, artifact_id, file_id, hash, size, role,
|
|
114
122
|
source_step, source_run, created_at, file_type
|
|
115
123
|
FROM cortex_artifacts
|
|
116
124
|
WHERE analysis_id = $1 AND source_run = $2 AND source_step = $3
|
|
117
125
|
AND artifact_id IS NOT NULL AND file_id IS NULL
|
|
118
126
|
AND role = 'step_output'
|
|
119
127
|
ORDER BY created_at`,
|
|
120
|
-
|
|
128
|
+
values: [resourceId, runId, stepId],
|
|
129
|
+
});
|
|
130
|
+
return result.rows.map(mapArtifactRow);
|
|
121
131
|
});
|
|
122
|
-
return result.rows.map(mapArtifactRow);
|
|
123
132
|
}
|
|
124
133
|
/**
|
|
125
134
|
* The artifacts a completed step registered, most consequential first. Ordered
|
|
@@ -127,11 +136,12 @@ export async function queryUnsyncedStepArtifacts(pool, resourceId, runId, stepId
|
|
|
127
136
|
* path, so a `limit` truncates the tail of the list rather than an arbitrary
|
|
128
137
|
* slice of it — and so the same call replays to the same rows.
|
|
129
138
|
*/
|
|
130
|
-
export
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
export function queryStepArtifactPaths(pool, resourceId, runId, stepId, limit) {
|
|
140
|
+
return tryQuery("artifacts.queryStepArtifactPaths", async () => {
|
|
141
|
+
if (limit <= 0)
|
|
142
|
+
return [];
|
|
143
|
+
const result = await pool.query({
|
|
144
|
+
text: `SELECT path, file_type
|
|
135
145
|
FROM cortex_artifacts
|
|
136
146
|
WHERE analysis_id = $1 AND source_run = $2 AND source_step = $3
|
|
137
147
|
AND role = 'step_output'
|
|
@@ -144,9 +154,10 @@ export async function queryStepArtifactPaths(pool, resourceId, runId, stepId, li
|
|
|
144
154
|
END,
|
|
145
155
|
path
|
|
146
156
|
LIMIT $4`,
|
|
147
|
-
|
|
157
|
+
values: [resourceId, runId, stepId, limit],
|
|
158
|
+
});
|
|
159
|
+
return result.rows.map((r) => ({ path: r.path, fileType: r.file_type ?? null }));
|
|
148
160
|
});
|
|
149
|
-
return result.rows.map((r) => ({ path: r.path, fileType: r.file_type ?? null }));
|
|
150
161
|
}
|
|
151
162
|
/**
|
|
152
163
|
* Every artifact of one analysis, ordered by path so the same call gives the same rows.
|
|
@@ -156,50 +167,58 @@ export async function queryStepArtifactPaths(pool, resourceId, runId, stepId, li
|
|
|
156
167
|
* query drops such a row, a later refusal says that the artifact never existed, and that reason is
|
|
157
168
|
* false.
|
|
158
169
|
*/
|
|
159
|
-
export
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
export function queryAnalysisArtifacts(pool, analysisId) {
|
|
171
|
+
return tryQuery("artifacts.queryAnalysisArtifacts", async () => {
|
|
172
|
+
const result = await pool.query({
|
|
173
|
+
text: `SELECT path, hash, file_type
|
|
162
174
|
FROM cortex_artifacts
|
|
163
175
|
WHERE analysis_id = $1
|
|
164
176
|
ORDER BY path`,
|
|
165
|
-
|
|
177
|
+
values: [analysisId],
|
|
178
|
+
});
|
|
179
|
+
return result.rows.map((r) => ({ path: r.path, hash: r.hash, fileType: r.file_type ?? null }));
|
|
166
180
|
});
|
|
167
|
-
return result.rows.map((r) => ({ path: r.path, hash: r.hash, fileType: r.file_type ?? null }));
|
|
168
181
|
}
|
|
169
182
|
/** Count step-output artifacts produced by a run — for the run-completed card. */
|
|
170
|
-
export
|
|
171
|
-
|
|
172
|
-
|
|
183
|
+
export function countArtifactsForRun(pool, analysisId, runId) {
|
|
184
|
+
return tryQuery("artifacts.countArtifactsForRun", async () => {
|
|
185
|
+
const result = await pool.query({
|
|
186
|
+
text: `SELECT COUNT(*)::text AS n
|
|
173
187
|
FROM cortex_artifacts
|
|
174
188
|
WHERE analysis_id = $1 AND source_run = $2 AND role = 'step_output'`,
|
|
175
|
-
|
|
189
|
+
values: [analysisId, runId],
|
|
190
|
+
});
|
|
191
|
+
return Number(result.rows[0]?.n ?? 0);
|
|
176
192
|
});
|
|
177
|
-
return Number(result.rows[0]?.n ?? 0);
|
|
178
193
|
}
|
|
179
|
-
export
|
|
180
|
-
|
|
181
|
-
|
|
194
|
+
export function updateArtifactId(pool, resourceId, path, artifactId, fileType) {
|
|
195
|
+
return tryMutation("artifacts.updateArtifactId", async () => {
|
|
196
|
+
await pool.query({
|
|
197
|
+
text: `UPDATE cortex_artifacts SET artifact_id = $1,
|
|
182
198
|
file_type = COALESCE($4, file_type)
|
|
183
199
|
WHERE analysis_id = $2 AND path = $3`,
|
|
184
|
-
|
|
200
|
+
values: [artifactId, resourceId, path, fileType ?? null],
|
|
201
|
+
});
|
|
185
202
|
});
|
|
186
203
|
}
|
|
187
|
-
export
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
204
|
+
export function updateFileIds(pool, pairs) {
|
|
205
|
+
return tryMutation("artifacts.updateFileIds", async () => {
|
|
206
|
+
if (pairs.length === 0)
|
|
207
|
+
return;
|
|
208
|
+
const values = [];
|
|
209
|
+
const tuples = [];
|
|
210
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
211
|
+
const base = i * 2;
|
|
212
|
+
tuples.push(`($${base + 1}::text, $${base + 2}::text)`);
|
|
213
|
+
values.push(pairs[i].artifactId, pairs[i].fileId);
|
|
214
|
+
}
|
|
215
|
+
await pool.query({
|
|
216
|
+
text: `UPDATE cortex_artifacts AS a
|
|
199
217
|
SET file_id = c.file_id
|
|
200
218
|
FROM (VALUES ${tuples.join(", ")}) AS c(artifact_id, file_id)
|
|
201
219
|
WHERE a.artifact_id = c.artifact_id`,
|
|
202
|
-
|
|
220
|
+
values,
|
|
221
|
+
});
|
|
203
222
|
});
|
|
204
223
|
}
|
|
205
224
|
function mapArtifactRow(row) {
|
|
@@ -146,9 +146,9 @@ export declare function expireStaleDataProfile(pool: Querier, analysisId: string
|
|
|
146
146
|
* Reset a ledger row wedged at `running` with no workflow behind it back to
|
|
147
147
|
* `failed`, so the normal retry path can re-profile it.
|
|
148
148
|
*
|
|
149
|
-
* A start that
|
|
149
|
+
* A start that fails after the CAS already flipped the row to `running`
|
|
150
150
|
* compensates itself (`triggerDataProfile`/`runDataProfile` fail the ledger in
|
|
151
|
-
* their
|
|
151
|
+
* their dispatch). This covers the residual case that compensation cannot: a host
|
|
152
152
|
* that dies in the window between the CAS and the `DBOS.startWorkflow` insert
|
|
153
153
|
* leaves a `running` row with no workflow for recovery to resume — nothing
|
|
154
154
|
* would ever move it off `running`, and every later trigger reports
|