@inflexa-ai/harness 0.44.0 → 0.45.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/app/approve-plan.d.ts +48 -0
- package/dist/app/approve-plan.js +84 -0
- package/dist/app/data-profile-view.d.ts +1 -1
- package/dist/app/run-activity.js +4 -6
- package/dist/contracts/chat-events.d.ts +2 -0
- package/dist/contracts/chat-frame.d.ts +7 -0
- package/dist/contracts/chat-frame.js +18 -4
- package/dist/contracts/chat-parts.d.ts +73 -2
- package/dist/contracts/chat-parts.js +3 -1
- package/dist/contracts/index.d.ts +3 -1
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/part-registry.js +3 -0
- package/dist/contracts/schemas/chat-events.d.ts +13 -0
- package/dist/contracts/schemas/chat-events.js +1 -0
- package/dist/contracts/schemas/chat-parts.d.ts +200 -15
- package/dist/contracts/schemas/chat-parts.js +63 -12
- package/dist/contracts/schemas/index.d.ts +1 -1
- package/dist/contracts/schemas/index.js +1 -1
- package/dist/contracts/subagent-activity.d.ts +12 -0
- package/dist/contracts/subagent-activity.js +76 -0
- package/dist/execution/artifact-metadata.js +1 -3
- package/dist/execution/run-canceler.js +1 -1
- package/dist/execution/run-event-parts.d.ts +6 -5
- package/dist/execution/run-event-parts.js +6 -5
- package/dist/execution/run-event-stream.d.ts +18 -6
- package/dist/execution/run-event-stream.js +67 -17
- package/dist/execution/run-synthesis.d.ts +21 -0
- package/dist/execution/run-synthesis.js +77 -3
- package/dist/index.d.ts +22 -8
- package/dist/index.js +16 -2
- package/dist/lib/hooks.d.ts +1 -1
- package/dist/lib/metrics.d.ts +2 -2
- package/dist/loop/run-agent.js +1 -0
- package/dist/loop/types.d.ts +2 -0
- package/dist/memory/card-builders.d.ts +11 -0
- package/dist/memory/card-builders.js +35 -21
- package/dist/memory/conversation-display-recorder.d.ts +2 -0
- package/dist/memory/conversation-display-recorder.js +10 -1
- package/dist/memory/conversation-display-storage.d.ts +9 -2
- package/dist/memory/conversation-display-storage.js +18 -3
- package/dist/memory/thread-history.d.ts +8 -1
- package/dist/memory/thread-history.js +13 -3
- package/dist/memory/thread-store.d.ts +13 -0
- package/dist/memory/thread-store.js +15 -1
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +3 -1
- package/dist/provenance/seam.d.ts +16 -5
- package/dist/providers/ai-sdk.js +6 -4
- package/dist/report-model/pin-snapshot.d.ts +1 -1
- package/dist/report-model/pin-snapshot.js +2 -50
- package/dist/runtime/assemble.d.ts +8 -1
- package/dist/runtime/assemble.js +11 -0
- package/dist/runtime/boot.d.ts +3 -0
- package/dist/runtime/boot.js +10 -1
- package/dist/sandbox/sandbox-step-translate.d.ts +23 -0
- package/dist/sandbox/sandbox-step-translate.js +24 -0
- package/dist/schemas/artifact-manifest.d.ts +1 -1
- package/dist/schemas/artifact-manifest.js +11 -9
- package/dist/schemas/plan-schemas.d.ts +18 -18
- package/dist/schemas/run-synthesis.d.ts +2 -2
- package/dist/state/analyses-metrics.d.ts +79 -7
- package/dist/state/analyses-metrics.js +141 -6
- package/dist/state/artifacts.d.ts +50 -3
- package/dist/state/artifacts.js +67 -7
- package/dist/state/data-profile.d.ts +4 -2
- package/dist/state/data-profile.js +7 -5
- package/dist/state/index.d.ts +9 -8
- package/dist/state/index.js +5 -5
- package/dist/state/migrations/20261012120000_index_the_runs_by_start.d.ts +8 -0
- package/dist/state/migrations/20261012120000_index_the_runs_by_start.js +12 -0
- package/dist/state/migrations/20261013120000_index_the_ended_runs_and_the_recent_threads.d.ts +8 -0
- package/dist/state/migrations/20261013120000_index_the_ended_runs_and_the_recent_threads.js +13 -0
- package/dist/state/migrations/20261013180000_narrow_the_active_run_index.d.ts +8 -0
- package/dist/state/migrations/20261013180000_narrow_the_active_run_index.js +13 -0
- package/dist/state/migrations/20261014120000_index_the_plans_by_parent_and_the_runs_by_plan.d.ts +8 -0
- package/dist/state/migrations/20261014120000_index_the_plans_by_parent_and_the_runs_by_plan.js +13 -0
- package/dist/state/migrations/index.js +8 -0
- package/dist/state/plans.d.ts +21 -0
- package/dist/state/plans.js +25 -0
- package/dist/state/runs.d.ts +36 -5
- package/dist/state/runs.js +65 -19
- package/dist/state/schema.d.ts +2 -0
- package/dist/tasks/data-profile-activity.d.ts +7 -1
- package/dist/tasks/data-profile-activity.js +18 -9
- package/dist/tasks/data-profile.d.ts +15 -1
- package/dist/tasks/data-profile.js +16 -11
- package/dist/tools/approval/gateway.js +28 -5
- package/dist/tools/display/show-user.d.ts +1 -1
- package/dist/tools/execute-analysis.d.ts +51 -0
- package/dist/tools/execute-analysis.js +241 -109
- package/dist/tools/research/inspect-data-profile.d.ts +1 -1
- package/dist/tools/research/inspect-run.d.ts +1 -1
- package/dist/tools/research/inspect-run.js +7 -7
- package/dist/workflows/execute-analysis.d.ts +4 -3
- package/dist/workflows/execute-analysis.js +35 -22
- package/dist/workflows/plan/graph.d.ts +16 -0
- package/dist/workflows/plan/graph.js +36 -0
- package/dist/workflows/sandbox-step.js +14 -12
- package/package.json +1 -1
|
@@ -36,6 +36,11 @@ import type { ChatPart } from "../contracts/chat-parts.js";
|
|
|
36
36
|
import { type DbError } from "../lib/db-result.js";
|
|
37
37
|
import type { Logger } from "../lib/logger.js";
|
|
38
38
|
import type { RunStatus } from "../state/schema.js";
|
|
39
|
+
/** The part of a run row that the terminal part is made from. */
|
|
40
|
+
export interface RunEventRunRead {
|
|
41
|
+
readonly status: RunStatus;
|
|
42
|
+
readonly error: string | null;
|
|
43
|
+
}
|
|
39
44
|
/**
|
|
40
45
|
* Construction-time dependencies. The pool is the application pool the run
|
|
41
46
|
* ledger lives in; the logger is where every contained failure is reported, and
|
|
@@ -45,8 +50,13 @@ import type { RunStatus } from "../state/schema.js";
|
|
|
45
50
|
export interface RunEventStreamDeps {
|
|
46
51
|
readonly pool: Pool;
|
|
47
52
|
readonly logger?: Logger;
|
|
48
|
-
/** Reads the status of the run row, `null` when no row exists. Defaults to `queryRun` on `pool`. */
|
|
49
|
-
readonly
|
|
53
|
+
/** Reads the status and the error of the run row, `null` when no row exists. Defaults to `queryRun` on `pool`. */
|
|
54
|
+
readonly readRun?: (runId: string) => ResultAsync<RunEventRunRead | null, DbError>;
|
|
55
|
+
/**
|
|
56
|
+
* Reads the status of the parent workflow in the durability engine, `null` when no workflow exists. Defaults to
|
|
57
|
+
* `DBOS.getWorkflowStatus`.
|
|
58
|
+
*/
|
|
59
|
+
readonly readWorkflowStatus?: (runId: string) => Promise<string | null>;
|
|
50
60
|
/** The wait between two reads of the run row. Defaults to a timer. */
|
|
51
61
|
readonly sleep?: (ms: number) => Promise<void>;
|
|
52
62
|
}
|
|
@@ -78,10 +88,12 @@ export interface RunEventStream {
|
|
|
78
88
|
* aborts.
|
|
79
89
|
*
|
|
80
90
|
* A canceled workflow runs no more steps, thus it never writes its own
|
|
81
|
-
* terminal part, and the canceler cannot write a stream. When
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
91
|
+
* terminal part, and the canceler cannot write a stream. When every stream
|
|
92
|
+
* ends with no `data-run-completed` or `data-run-failed` part, the last
|
|
93
|
+
* part delivered is a `data-run-failed` part that the run row gives, or the
|
|
94
|
+
* status of the parent workflow when the row still reads `running`. A row
|
|
95
|
+
* that does not exist, a `completed` or `partial` row, an active workflow,
|
|
96
|
+
* and no workflow give no part.
|
|
85
97
|
*
|
|
86
98
|
* Parts from one workflow arrive in the order that workflow wrote them. No
|
|
87
99
|
* order is promised ACROSS the parent and its children: those workflows
|
|
@@ -37,6 +37,28 @@ import { describeDbError } from "../lib/db-result.js";
|
|
|
37
37
|
import { queryRun } from "../state/runs.js";
|
|
38
38
|
import { queryStepsByRun } from "../state/step-executions.js";
|
|
39
39
|
import { foldRunEventParts, parseRunEventPart } from "./run-event-parts.js";
|
|
40
|
+
const canceledPart = (runId) => ({ type: "data-run-failed", runId, error: "Run canceled", reason: "canceled" });
|
|
41
|
+
/** The terminal part that a settled run row gives, or `null` when the body of the run writes the part. */
|
|
42
|
+
function partOfRow(runId, row) {
|
|
43
|
+
switch (row.status) {
|
|
44
|
+
case "canceled":
|
|
45
|
+
return canceledPart(runId);
|
|
46
|
+
case "suspended_insufficient_funds":
|
|
47
|
+
return row.error === null
|
|
48
|
+
? { type: "data-run-failed", runId, error: "Run suspended" }
|
|
49
|
+
: { type: "data-run-failed", runId, error: row.error, reason: row.error };
|
|
50
|
+
case "failed":
|
|
51
|
+
return { type: "data-run-failed", runId, error: row.error ?? "Run failed" };
|
|
52
|
+
case "completed":
|
|
53
|
+
case "partial":
|
|
54
|
+
case "running":
|
|
55
|
+
return null;
|
|
56
|
+
default: {
|
|
57
|
+
const _exhaustive = row.status;
|
|
58
|
+
throw new Error(`unhandled run status: ${String(_exhaustive)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
40
62
|
/** Durable stream key every run producer writes its parts under. */
|
|
41
63
|
const RUN_EVENT_STREAM_KEY = "events";
|
|
42
64
|
/**
|
|
@@ -58,8 +80,8 @@ const CHILD_DISCOVERY_INTERVAL_MS = 1_000;
|
|
|
58
80
|
* the stream can end before the row changes, and the later reads wait out that
|
|
59
81
|
* window.
|
|
60
82
|
*/
|
|
61
|
-
const
|
|
62
|
-
const
|
|
83
|
+
const TERMINAL_ROW_READ_ATTEMPTS = 4;
|
|
84
|
+
const TERMINAL_ROW_READ_INTERVAL_MS = 500;
|
|
63
85
|
/**
|
|
64
86
|
* Build the DBOS-backed realization of {@link RunEventStream}.
|
|
65
87
|
*
|
|
@@ -72,7 +94,8 @@ const CANCELED_ROW_READ_INTERVAL_MS = 500;
|
|
|
72
94
|
*/
|
|
73
95
|
export function createRunEventStream(deps) {
|
|
74
96
|
const baseLogger = (deps.logger ?? createNoopLogger()).named("run-event-stream");
|
|
75
|
-
const
|
|
97
|
+
const readRun = deps.readRun ?? ((runId) => queryRun(deps.pool, runId).map((row) => (row === null ? null : { status: row.status, error: row.error })));
|
|
98
|
+
const readWorkflowStatus = deps.readWorkflowStatus ?? (async (runId) => (await DBOS.getWorkflowStatus(runId))?.status ?? null);
|
|
76
99
|
const waitForRowRead = deps.sleep ?? sleep;
|
|
77
100
|
return {
|
|
78
101
|
async subscribe({ runId, onPart, signal }) {
|
|
@@ -210,37 +233,64 @@ export function createRunEventStream(deps) {
|
|
|
210
233
|
await Promise.race([sleep(CHILD_DISCOVERY_INTERVAL_MS), aborted, parentRead]);
|
|
211
234
|
}
|
|
212
235
|
})();
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
236
|
+
const workflowTerminalPart = async () => {
|
|
237
|
+
let workflowStatus;
|
|
238
|
+
try {
|
|
239
|
+
workflowStatus = await readWorkflowStatus(runId);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
logger.warn("workflow status read failed", logger.errorFields(err));
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
switch (workflowStatus) {
|
|
246
|
+
case "CANCELLED":
|
|
247
|
+
return canceledPart(runId);
|
|
248
|
+
case "ERROR":
|
|
249
|
+
case "MAX_RECOVERY_ATTEMPTS_EXCEEDED":
|
|
250
|
+
case "SUCCESS":
|
|
251
|
+
return { type: "data-run-failed", runId, error: "Run ended without a terminal status" };
|
|
252
|
+
case "PENDING":
|
|
253
|
+
case "ENQUEUED":
|
|
254
|
+
case "DELAYED":
|
|
255
|
+
logger.warn("run streams ended while the workflow is active", { workflowStatus });
|
|
256
|
+
return null;
|
|
257
|
+
default:
|
|
258
|
+
// No workflow: the launch did not start it, or it never started. An unknown status gives no part too.
|
|
259
|
+
if (workflowStatus !== null)
|
|
260
|
+
logger.warn("unknown workflow status", { workflowStatus });
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
const missingTerminalPart = async () => {
|
|
265
|
+
let rowReadsRunning = false;
|
|
266
|
+
for (let attempt = 1; attempt <= TERMINAL_ROW_READ_ATTEMPTS; attempt++) {
|
|
267
|
+
const read = await readRun(runId);
|
|
268
|
+
rowReadsRunning = false;
|
|
216
269
|
if (read.isErr()) {
|
|
217
270
|
logger.warn("run row read failed", { err: describeDbError(read.error) });
|
|
218
271
|
}
|
|
219
272
|
else {
|
|
220
|
-
const status = read.value;
|
|
221
|
-
if (status === "canceled")
|
|
222
|
-
return { type: "data-run-failed", runId, error: "Run canceled", reason: "canceled" };
|
|
223
273
|
// The launch writes the row before the workflow starts, thus
|
|
224
274
|
// no row means that the id is not an analysis run.
|
|
225
|
-
if (
|
|
226
|
-
return null;
|
|
227
|
-
// Only an active row can still become `canceled`.
|
|
228
|
-
if (status !== "running" && status !== "suspended_insufficient_funds")
|
|
275
|
+
if (read.value === null)
|
|
229
276
|
return null;
|
|
277
|
+
if (read.value.status !== "running")
|
|
278
|
+
return partOfRow(runId, read.value);
|
|
279
|
+
rowReadsRunning = true;
|
|
230
280
|
}
|
|
231
|
-
if (attempt <
|
|
232
|
-
await Promise.race([waitForRowRead(
|
|
281
|
+
if (attempt < TERMINAL_ROW_READ_ATTEMPTS)
|
|
282
|
+
await Promise.race([waitForRowRead(TERMINAL_ROW_READ_INTERVAL_MS), aborted]);
|
|
233
283
|
if (signal.aborted)
|
|
234
284
|
return null;
|
|
235
285
|
}
|
|
236
|
-
return null;
|
|
286
|
+
return rowReadsRunning ? workflowTerminalPart() : null;
|
|
237
287
|
};
|
|
238
288
|
const settled = (async () => {
|
|
239
289
|
await discovery;
|
|
240
290
|
await parentRead;
|
|
241
291
|
await Promise.all(childReads);
|
|
242
292
|
if (!sawTerminal && !signal.aborted) {
|
|
243
|
-
const terminal = await
|
|
293
|
+
const terminal = await missingTerminalPart();
|
|
244
294
|
if (terminal !== null)
|
|
245
295
|
pending.push(terminal);
|
|
246
296
|
}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* `failed` part. We do not throw here for routine submitter rejections.
|
|
25
25
|
*/
|
|
26
26
|
import { type RunSynthesis } from "../schemas/run-synthesis.js";
|
|
27
|
+
import type { RunSynthesisPart } from "../contracts/chat-parts.js";
|
|
27
28
|
import type { StepSummary } from "../schemas/step-summary.js";
|
|
28
29
|
import type { ToolOutputStore } from "../loop/tool-output.js";
|
|
29
30
|
import type { ChatDataPart, EmitFn } from "../loop/types.js";
|
|
@@ -119,6 +120,26 @@ export interface PersistSynthesisInput {
|
|
|
119
120
|
readonly synthesis: RunSynthesis;
|
|
120
121
|
}
|
|
121
122
|
export declare function persistSynthesis(args: PersistSynthesisInput): Promise<string>;
|
|
123
|
+
export interface ReadSynthesisInput {
|
|
124
|
+
/** Absolute host root of the analysis's workspace tree. */
|
|
125
|
+
readonly workspaceRoot: string;
|
|
126
|
+
readonly runId: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Read the text of a synthesis record under the cap, or give `undefined` when the bytes do not come back.
|
|
130
|
+
*
|
|
131
|
+
* The read takes a bounded byte window, thus a file of any size costs the cap. A run id that can escape
|
|
132
|
+
* the run tree, an absent file, a genuine read fault, and a file over the cap each give `undefined`,
|
|
133
|
+
* because a collection reports no error for one record.
|
|
134
|
+
*/
|
|
135
|
+
export declare function readSynthesisText(args: ReadSynthesisInput): Promise<string | undefined>;
|
|
136
|
+
/**
|
|
137
|
+
* The validated synthesis record of a run as the flat `data-run-synthesis` part, the shape that the run
|
|
138
|
+
* stream carries for the same record. It gives `null` for each fault of {@link readSynthesisText}, for text
|
|
139
|
+
* that is not JSON, and for JSON that fails {@link RunSynthesisSchema}. The run row stays the authority on
|
|
140
|
+
* whether a synthesis exists, thus the read does not consult it.
|
|
141
|
+
*/
|
|
142
|
+
export declare function readRunSynthesis(args: ReadSynthesisInput): Promise<RunSynthesisPart | null>;
|
|
122
143
|
export declare function formatSynthesisEmbeddingText(synthesis: RunSynthesis): string;
|
|
123
144
|
/**
|
|
124
145
|
* Build the `data-run-synthesis` chat part the parent stream emits when the
|
|
@@ -23,16 +23,18 @@
|
|
|
23
23
|
* resolves with `{ kind: "failed" }`, the wrapper emits a synthesis-progress
|
|
24
24
|
* `failed` part. We do not throw here for routine submitter rejections.
|
|
25
25
|
*/
|
|
26
|
-
import { readFile } from "node:fs/promises";
|
|
26
|
+
import { open, readFile } from "node:fs/promises";
|
|
27
27
|
import { join } from "node:path";
|
|
28
28
|
import { ok } from "neverthrow";
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
import { writeFileWithinRoot } from "../lib/fs-helpers.js";
|
|
31
|
+
import { tryFs } from "../lib/fs-result.js";
|
|
31
32
|
import { hintForZodIssue } from "../lib/zod-issues.js";
|
|
32
33
|
import { BiologicalThemeSchema, KeyReferenceSchema, RunSynthesisSchema, SynthesizedFindingSchema, } from "../schemas/run-synthesis.js";
|
|
33
34
|
import { synthesisAgentPrompt } from "../prompts/synthesis-agent.js";
|
|
34
35
|
import { composeSystemPrompt } from "../agents/system-prompt.js";
|
|
35
|
-
import {
|
|
36
|
+
import { flattenDataPart } from "../contracts/chat-frame.js";
|
|
37
|
+
import { isSafeId, runDir } from "../workspace/paths.js";
|
|
36
38
|
import { decodeObjectString } from "../lib/zod-issues.js";
|
|
37
39
|
import { runToTerminal } from "../loop/run-to-terminal.js";
|
|
38
40
|
import { passthroughStep } from "../loop/run-step.js";
|
|
@@ -435,15 +437,87 @@ export async function loadStepSummariesFromDisk(args) {
|
|
|
435
437
|
}
|
|
436
438
|
return out;
|
|
437
439
|
}
|
|
440
|
+
/** The file name of the synthesis record inside the run directory. */
|
|
441
|
+
const SYNTHESIS_FILE = "synthesis.json";
|
|
442
|
+
/**
|
|
443
|
+
* The cap of one synthesis read. A synthesis record is small by construction, and the cap bounds the
|
|
444
|
+
* cost of a file that is not. A file over the cap gives no text, because a cut JSON text cannot parse.
|
|
445
|
+
*/
|
|
446
|
+
const SYNTHESIS_CAP_BYTES = 1024 * 1024;
|
|
438
447
|
export async function persistSynthesis(args) {
|
|
439
448
|
// Confine to the run directory, not the whole workspace: synthesis.json sits
|
|
440
449
|
// at runs/{runId}/, above any step's RW mount and never in the hard-linked
|
|
441
450
|
// `data/` inputs.
|
|
442
451
|
const runRoot = join(args.workspaceRoot, runDir(args.runId));
|
|
443
|
-
const path = join(runRoot,
|
|
452
|
+
const path = join(runRoot, SYNTHESIS_FILE);
|
|
444
453
|
await writeFileWithinRoot(runRoot, path, JSON.stringify(args.synthesis, null, 2));
|
|
445
454
|
return path;
|
|
446
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Read the text of a synthesis record under the cap, or give `undefined` when the bytes do not come back.
|
|
458
|
+
*
|
|
459
|
+
* The read takes a bounded byte window, thus a file of any size costs the cap. A run id that can escape
|
|
460
|
+
* the run tree, an absent file, a genuine read fault, and a file over the cap each give `undefined`,
|
|
461
|
+
* because a collection reports no error for one record.
|
|
462
|
+
*/
|
|
463
|
+
export async function readSynthesisText(args) {
|
|
464
|
+
// The path builder refuses an id that can escape the run tree with a throw. The guard keeps the read on
|
|
465
|
+
// the value channel.
|
|
466
|
+
if (!isSafeId(args.runId)) {
|
|
467
|
+
return undefined;
|
|
468
|
+
}
|
|
469
|
+
const absolute = join(args.workspaceRoot, runDir(args.runId), SYNTHESIS_FILE);
|
|
470
|
+
return tryFs("runSynthesis.readText", async () => {
|
|
471
|
+
const handle = await open(absolute, "r");
|
|
472
|
+
try {
|
|
473
|
+
// The window takes one byte more than the cap. A read that fills it states that the file
|
|
474
|
+
// holds more bytes than the cap admits, thus the two conditions stay apart.
|
|
475
|
+
const buffer = Buffer.alloc(SYNTHESIS_CAP_BYTES + 1);
|
|
476
|
+
// One read of a network-backed file can give fewer bytes than the window holds. Such a
|
|
477
|
+
// short read cuts the text in the middle of the JSON, and the record then parses to no
|
|
478
|
+
// key at all. Thus the loop reads again from the offset that the last read reached, and
|
|
479
|
+
// it stops when the window fills or when a read gives no byte.
|
|
480
|
+
let filled = 0;
|
|
481
|
+
while (filled < buffer.length) {
|
|
482
|
+
const { bytesRead } = await handle.read(buffer, filled, buffer.length - filled, filled);
|
|
483
|
+
if (bytesRead === 0) {
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
filled += bytesRead;
|
|
487
|
+
}
|
|
488
|
+
return filled > SYNTHESIS_CAP_BYTES ? undefined : buffer.subarray(0, filled).toString("utf8");
|
|
489
|
+
}
|
|
490
|
+
finally {
|
|
491
|
+
await handle.close();
|
|
492
|
+
}
|
|
493
|
+
}, { path: absolute, onAbsent: () => undefined }).unwrapOr(undefined);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* The validated synthesis record of a run as the flat `data-run-synthesis` part, the shape that the run
|
|
497
|
+
* stream carries for the same record. It gives `null` for each fault of {@link readSynthesisText}, for text
|
|
498
|
+
* that is not JSON, and for JSON that fails {@link RunSynthesisSchema}. The run row stays the authority on
|
|
499
|
+
* whether a synthesis exists, thus the read does not consult it.
|
|
500
|
+
*/
|
|
501
|
+
export async function readRunSynthesis(args) {
|
|
502
|
+
const text = await readSynthesisText(args);
|
|
503
|
+
if (text === undefined) {
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
let json;
|
|
507
|
+
try {
|
|
508
|
+
json = JSON.parse(text);
|
|
509
|
+
}
|
|
510
|
+
catch {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
const parsed = RunSynthesisSchema.safeParse(json);
|
|
514
|
+
if (!parsed.success) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
// The payload comes from a validated `RunSynthesis`, and the builder sets each field of the part contract.
|
|
518
|
+
// The tests parse the result with `RunSynthesisPartSchema`.
|
|
519
|
+
return flattenDataPart(buildRunSynthesisPart(args.runId, parsed.data));
|
|
520
|
+
}
|
|
447
521
|
// ── Embedding text ──────────────────────────────────────────────────
|
|
448
522
|
export function formatSynthesisEmbeddingText(synthesis) {
|
|
449
523
|
return [
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export { resolveCompositionEyes } from "./runtime/assemble.js";
|
|
|
16
16
|
export type { ThreadAgentResolver, UnregisteredThreadType } from "./runtime/assemble.js";
|
|
17
17
|
export { createReportSessionSpawn } from "./app/spawn-report-session.js";
|
|
18
18
|
export type { ReportSessionSpawn, ReportSessionSpawnDeps, ReportSessionPaging, SpawnRefusal, ReportBrief, ReportSessionDelta, NewestReportChild, } from "./app/spawn-report-session.js";
|
|
19
|
+
export { launchPlanRun } from "./tools/execute-analysis.js";
|
|
20
|
+
export type { LaunchPlanRunDeps, LaunchPlanRunRefusal, PlanLaunch } from "./tools/execute-analysis.js";
|
|
21
|
+
export { approvePlan } from "./app/approve-plan.js";
|
|
22
|
+
export type { ApprovePlanDeps, ApprovePlanInput, ApprovePlanRefusal, PlanApproval } from "./app/approve-plan.js";
|
|
19
23
|
export type { EnsureSessionStateResult } from "./app/report-session-runtime.js";
|
|
20
24
|
export { bootHarness } from "./runtime/boot.js";
|
|
21
25
|
export type { BootHarnessDeps, BootedHarness } from "./runtime/boot.js";
|
|
@@ -85,7 +89,7 @@ export { createStreamingChat } from "./providers/streaming-chat.js";
|
|
|
85
89
|
export { openChatTurn, prepareChatTurn, runChatTurn } from "./app/chat-turn.js";
|
|
86
90
|
export type { ChatTurnOutcome, ChatTurnRan, ChatTurnRefusal, ChatTurnResult, ChatTurnSession, OpenChatTurn, OpenChatTurnParams, PrepareChatTurnDeps, PrepareChatTurnParams, PrepareChatTurnResult, RunChatTurnDeps, RunChatTurnParams, RunOpenChatTurnParams, } from "./app/chat-turn.js";
|
|
87
91
|
export { createThreadStore } from "./memory/thread-store.js";
|
|
88
|
-
export type { ThreadStore, Thread, ThreadType, ThreadInputError, CreateThreadInput, ListThreadsInput, ThreadPage } from "./memory/thread-store.js";
|
|
92
|
+
export type { ThreadStore, Thread, ThreadType, ThreadInputError, CreateThreadInput, ListThreadsInput, ListRecentThreadsInput, ThreadPage, } from "./memory/thread-store.js";
|
|
89
93
|
export { createThreadHistory, conversationRecordTurn } from "./memory/thread-history.js";
|
|
90
94
|
export type { ThreadHistory, StoredMessage, RetractOutcome, ConversationTurn, TurnWrite, TurnWriteResult, TurnClose, TurnStatus, StoredTurnRecord, } from "./memory/thread-history.js";
|
|
91
95
|
export { syntheticUserMessage, syntheticRecordMessage, isSyntheticUserMessage, isSyntheticRecordMessage } from "./memory/ai-sdk-message-storage.js";
|
|
@@ -96,10 +100,12 @@ export type { ConversationDisplayMetadata, ConversationUIData, ConversationUIMes
|
|
|
96
100
|
export { storedMessagesToChat } from "./memory/conversation-display-replay.js";
|
|
97
101
|
export type { ChatEvent, ChatFrame, ChatPartFrame, TextDeltaEvent, IterationEvent, ToolStartedEvent, ToolFinishedEvent, ToolOutcome, ToolCallOutcome, ToolCallDetail, FinishEvent, ChatErrorEvent, } from "./contracts/chat-events.js";
|
|
98
102
|
export { toChatFrame, applyChatFrame, checkChatPart } from "./contracts/chat-frame.js";
|
|
103
|
+
export { createSubAgentActivityTracker, SUBAGENT_ACTIVITY_MAX_ENTRIES } from "./contracts/subagent-activity.js";
|
|
104
|
+
export type { SubAgentActivityTracker } from "./contracts/subagent-activity.js";
|
|
99
105
|
export type { TextPart, ToolCallPart, MessagePart, ChatMessage } from "./contracts/message.js";
|
|
100
106
|
export type { TurnTerminal, ApplyFrameResult, ChatPartCheck } from "./contracts/chat-frame.js";
|
|
101
107
|
export type { TokenUsageRollup } from "./contracts/usage.js";
|
|
102
|
-
export type { ChatPart, PresentationPart, PresentationContent, PlanPart, RunCardPart, FileReferencePart, FileReferenceEntry, RunStartedPart, DagStatePart, DagStepState, StepStatus, StepActivityPart, StepPhase, StepFileTreePart, FileTreeEntry, StepOutputPart, StepOutputFile, StepSummaryPart, StepUsagePart, StepBlockedPart, RunSynthesisPart, SynthesizedFinding, BiologicalTheme, SynthesisProgressPart, SynthesisPhase, RunCompletedPart, RunCompletedFinding, RunFailedPart, CompactionPart, AskPart, ChildSessionStartedPart, ReportRenderedPart, } from "./contracts/chat-parts.js";
|
|
108
|
+
export type { ChatPart, PresentationPart, PresentationContent, PlanPart, RunCardPart, PlanApprovalPart, FileReferencePart, FileReferenceEntry, RunStartedPart, DagStatePart, DagStepState, PlanGraphStep, StepStatus, StepActivityPart, ActivityEntryPart, SubAgentActivityEntry, SubAgentActivityPart, StepPhase, StepFileTreePart, FileTreeEntry, StepOutputPart, StepOutputFile, StepSummaryPart, StepUsagePart, StepBlockedPart, RunSynthesisPart, FindingReference, SynthesizedFinding, BiologicalTheme, SynthesisProgressPart, SynthesisPhase, RunCompletedPart, RunCompletedFinding, RunFailedPart, CompactionPart, AskPart, ChildSessionStartedPart, ReportRenderedPart, } from "./contracts/chat-parts.js";
|
|
103
109
|
export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./contracts/part-registry.js";
|
|
104
110
|
export type { ChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./contracts/part-registry.js";
|
|
105
111
|
export { parseStructureUrl, alphafoldEntryUrl, alphafoldPredictionUrl } from "./contracts/structure-source.js";
|
|
@@ -115,7 +121,7 @@ export { createPool } from "./lib/storage.js";
|
|
|
115
121
|
export type { PoolConfig } from "./lib/storage.js";
|
|
116
122
|
export type { Pool } from "pg";
|
|
117
123
|
export { registerDataProfileWorkflow, triggerDataProfile, runDataProfile, describeDataProfileStartError } from "./tasks/data-profile.js";
|
|
118
|
-
export type { DataProfileDeps, DataProfileWorkflowInput, DataProfileTriggerDeps, DataProfileTriggerParams, DataProfileTriggerResult, DataProfileStartError, } from "./tasks/data-profile.js";
|
|
124
|
+
export type { DataProfileDeps, DataProfileWorkflowInput, DataProfileTriggerDeps, DataProfileTriggerParams, DataProfileTriggerResult, DataProfileStartError, DataProfileSettlement, NotifyDataProfileSettled, } from "./tasks/data-profile.js";
|
|
119
125
|
/**
|
|
120
126
|
* The synthetic run id the data-profile workflow stamps onto its own frame — the profile has no run
|
|
121
127
|
* row, so this literal is the only thing that identifies its work as the profile's.
|
|
@@ -132,6 +138,12 @@ export { upsertAnalysis } from "./state/analyses.js";
|
|
|
132
138
|
export { clearDataProfile, loadDataProfileStatus, tryRetryDataProfile, reconcileOrphanedDataProfile } from "./state/data-profile.js";
|
|
133
139
|
export type { DataProfileAxis, DataProfileChecked, DataProfileCompanionCompleteness, DataProfileCoverage, DataProfileDimension, DataProfileFile, DataProfileGroup, DataProfileGroupSlot, DataProfileInputSignature, DataProfileKind, DataProfileLifecycleStatus, DataProfileMemberAnnotation, DataProfileObservation, DataProfileOrganism, DataProfilePartition, DataProfileProbeReport, DataProfileQualityAssessment, DataProfileQuarantine, DataProfileRecipeStep, DataProfileResult, DataProfileSubjectSource, } from "./contracts/data-profile.js";
|
|
134
140
|
export type { DataProfileStatus } from "./state/data-profile.js";
|
|
141
|
+
export { queryLatestRunsByAnalyses, queryDataProfileStatusByAnalyses, queryRunProgressByRuns, queryRunsEndedSince } from "./state/analyses-metrics.js";
|
|
142
|
+
export type { DataProfileSummary, EndedRunSummary, LatestRunSummary, RunProgressSummary } from "./state/analyses-metrics.js";
|
|
143
|
+
export { queryArtifactPage, countArtifactsByRuns } from "./state/artifacts.js";
|
|
144
|
+
export type { ArtifactPage, ArtifactPageEntry, ArtifactPageQuery, ArtifactPageSort, RunArtifactCount } from "./state/artifacts.js";
|
|
145
|
+
export { readRunSynthesis } from "./execution/run-synthesis.js";
|
|
146
|
+
export type { ReadSynthesisInput } from "./execution/run-synthesis.js";
|
|
135
147
|
export { DIMENSION_CATEGORIES, DIMENSION_CATEGORY_IDS, DIMENSION_PROBES, DIMENSION_PROBE_IDS, GROUP_CATEGORIES, GROUP_CATEGORY_IDS, GROUP_ROLES, GROUP_ROLE_IDS, PROBE_OUTCOME_IDS, dimensionCategoryEntry, dimensionScope, groupCategoryEntry, } from "./contracts/profile-vocabulary.js";
|
|
136
148
|
export type { DimensionCategory, DimensionCategoryEntry, DimensionProbe, DimensionProbeEntry, DimensionScope, DimensionTreatment, GroupCategory, GroupCategoryEntry, GroupRole, GroupRoleEntry, ProbeOutcome, } from "./contracts/profile-vocabulary.js";
|
|
137
149
|
export { dimensionCardinalities, profileCaveats, profileDatasetFileCount, profileDimensions, profileFileRecords, profileGroups, } from "./app/data-profile-view.js";
|
|
@@ -165,22 +177,24 @@ export type { ExecuteAnalysisDeps, ExecuteAnalysisInput, ExecuteAnalysisResult,
|
|
|
165
177
|
export { registerSandboxStep } from "./workflows/sandbox-step.js";
|
|
166
178
|
export type { SandboxStepDeps, SandboxStepInput, SandboxStepResult, SandboxAgentBuildContext } from "./workflows/sandbox-step.js";
|
|
167
179
|
export { createRunEventStream } from "./execution/run-event-stream.js";
|
|
168
|
-
export type { RunEventStream, RunEventStreamDeps, RunEventSubscribeOptions, RunEventPartHandler } from "./execution/run-event-stream.js";
|
|
180
|
+
export type { RunEventStream, RunEventStreamDeps, RunEventRunRead, RunEventSubscribeOptions, RunEventPartHandler } from "./execution/run-event-stream.js";
|
|
169
181
|
export { pipeFoldedRunEvents } from "./execution/run-event-parts.js";
|
|
170
182
|
export { createSandboxAgents, SANDBOX_AGENT_META } from "./agents/sandbox/index.js";
|
|
171
183
|
export type { SandboxAgentDeps, SandboxStepCoords, AgentMeta } from "./agents/sandbox/index.js";
|
|
172
184
|
export { AnalysisPlanSchema } from "./schemas/workflow-state.js";
|
|
173
185
|
export type { AnalysisPlan, AnalysisStep } from "./schemas/workflow-state.js";
|
|
174
186
|
export type { PlanStep } from "./workflows/execute-analysis-scheduler.js";
|
|
187
|
+
export { planGraphOf } from "./workflows/plan/graph.js";
|
|
188
|
+
export { planPartOf } from "./memory/card-builders.js";
|
|
175
189
|
export { validatePlan } from "./schemas/validate-plan.js";
|
|
176
190
|
export type { ValidatePlanOptions } from "./schemas/validate-plan.js";
|
|
177
191
|
export type { ValidationResult } from "./schemas/validate-plan.js";
|
|
178
|
-
export { upsertPlan, loadPlan } from "./state/plans.js";
|
|
179
|
-
export type { UpsertPlanInput } from "./state/plans.js";
|
|
180
|
-
export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
|
|
192
|
+
export { upsertPlan, loadPlan, loadPlanRecord } from "./state/plans.js";
|
|
193
|
+
export type { UpsertPlanInput, PlanRecord } from "./state/plans.js";
|
|
194
|
+
export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, queryRunIdsByPlan, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
|
|
181
195
|
export type { InsertRunInput, RunReservation } from "./state/runs.js";
|
|
182
196
|
export { queryStepsByRun } from "./state/step-executions.js";
|
|
183
|
-
export type { CortexRunRow, StepExecutionRow, RunStatus } from "./state/schema.js";
|
|
197
|
+
export type { CortexRunRow, StepExecutionRow, RunStatus, TerminalRunStatus } from "./state/schema.js";
|
|
184
198
|
export type { DbError } from "./lib/db-result.js";
|
|
185
199
|
export { REFERENCE_DATA_CATALOG, REFERENCE_DATA_CATALOG_VERSION, ReferenceArtifactPathSchema, ReferenceArtifactSchema, ReferenceDataCatalogSchema, ReferenceDatasetSchema, ReferenceSha256Schema, UnknownReferenceDatasetError, referenceArtifactKey, resolveReferenceInstallPlan, } from "./reference-data/catalog.js";
|
|
186
200
|
export type { ReferenceArtifact, ReferenceDataCatalog, ReferenceDataset, ReferenceInstallPlan, ReferenceInstallPlanDataset } from "./reference-data/catalog.js";
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,11 @@ export { resolveCompositionEyes } from "./runtime/assemble.js";
|
|
|
22
22
|
// the report sessions of one analysis. An embedder reaches the listing for its
|
|
23
23
|
// navigation surface, thus these names belong on the front door.
|
|
24
24
|
export { createReportSessionSpawn } from "./app/spawn-report-session.js";
|
|
25
|
+
// Start the run of a stored plan, and approve a plan by its id. Each gives a `Result` and never throws, thus
|
|
26
|
+
// a host route calls them with no `try`. `CoreRuntime.approvePlan` binds the approval over the deps of the
|
|
27
|
+
// conversation agent.
|
|
28
|
+
export { launchPlanRun } from "./tools/execute-analysis.js";
|
|
29
|
+
export { approvePlan } from "./app/approve-plan.js";
|
|
25
30
|
// The harness-owned boot sequence: ordered boot steps around `assembleCoreRuntime`
|
|
26
31
|
// (skill validation → state init → connection budget → assemble → launch) + a
|
|
27
32
|
// `shutdown` handle the embedder wires to its process signals.
|
|
@@ -156,6 +161,7 @@ export { envelopeDisplayMessages, parseStoredDisplayEnvelope } from "./memory/co
|
|
|
156
161
|
// by dropping that part, so one stale row cannot fail a whole thread.
|
|
157
162
|
export { storedMessagesToChat } from "./memory/conversation-display-replay.js";
|
|
158
163
|
export { toChatFrame, applyChatFrame, checkChatPart } from "./contracts/chat-frame.js";
|
|
164
|
+
export { createSubAgentActivityTracker, SUBAGENT_ACTIVITY_MAX_ENTRIES } from "./contracts/subagent-activity.js";
|
|
159
165
|
export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./contracts/part-registry.js";
|
|
160
166
|
// The source grammar of a `structure` presentation card — a host re-runs the same parse over a
|
|
161
167
|
// persisted `url` before it fetches, so the rule lives in one place for both sides.
|
|
@@ -215,6 +221,12 @@ export { upsertAnalysis } from "./state/analyses.js";
|
|
|
215
221
|
// analysis's input set empties (deferring on a running workflow), so the UI
|
|
216
222
|
// stops advertising a profile that describes files the analysis no longer has.
|
|
217
223
|
export { clearDataProfile, loadDataProfileStatus, tryRetryDataProfile, reconcileOrphanedDataProfile } from "./state/data-profile.js";
|
|
224
|
+
// The grouped reads that summarize a page of analyses: one statement for the whole list.
|
|
225
|
+
export { queryLatestRunsByAnalyses, queryDataProfileStatusByAnalyses, queryRunProgressByRuns, queryRunsEndedSince } from "./state/analyses-metrics.js";
|
|
226
|
+
// The artifact ledger reads of one analysis: one page with an exact total, and the step-output count of each run of a list in one statement.
|
|
227
|
+
export { queryArtifactPage, countArtifactsByRuns } from "./state/artifacts.js";
|
|
228
|
+
// The validated synthesis record of a run as the flat `data-run-synthesis` part of the run stream, or null.
|
|
229
|
+
export { readRunSynthesis } from "./execution/run-synthesis.js";
|
|
218
230
|
// The controlled vocabulary the profiler draws from, as data. A consumer rendering a
|
|
219
231
|
// stored group needs the category's meaning, and the package owns the catalogue — a host
|
|
220
232
|
// does not extend it.
|
|
@@ -277,12 +289,14 @@ export { createSandboxAgents, SANDBOX_AGENT_META } from "./agents/sandbox/index.
|
|
|
277
289
|
// an embedder supplies the plan's step DATA and the harness composes each step's
|
|
278
290
|
// seed at dispatch, when the step's dependencies have actually produced something.
|
|
279
291
|
export { AnalysisPlanSchema } from "./schemas/workflow-state.js";
|
|
292
|
+
export { planGraphOf } from "./workflows/plan/graph.js";
|
|
293
|
+
export { planPartOf } from "./memory/card-builders.js";
|
|
280
294
|
export { validatePlan } from "./schemas/validate-plan.js";
|
|
281
295
|
// Plan + run + step ledgers around a trigger. `upsertPlan` takes a
|
|
282
296
|
// caller-derived id and inserts-if-absent (the deterministic-id intake path);
|
|
283
297
|
// the run-state calls mirror the chat trigger's reserve → dedup → status flow.
|
|
284
|
-
export { upsertPlan, loadPlan } from "./state/plans.js";
|
|
285
|
-
export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
|
|
298
|
+
export { upsertPlan, loadPlan, loadPlanRecord } from "./state/plans.js";
|
|
299
|
+
export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, queryRunIdsByPlan, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
|
|
286
300
|
export { queryStepsByRun } from "./state/step-executions.js";
|
|
287
301
|
// Host-neutral reference-data catalog and shared installation receipts. Each
|
|
288
302
|
// artifact names the third-party upstream it is fetched from; embedders own all
|
package/dist/lib/hooks.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface NoticeFailure {
|
|
|
29
29
|
readonly reason: string;
|
|
30
30
|
}
|
|
31
31
|
export type GateName = "RunAuthorizer.authorize" | "RunCharge.open" | "ArtifactRegistry.register" | "resolveRequestHeaders" | "resolveSandboxLabels";
|
|
32
|
-
export type NoticeName = "RunAuthorizer.revoke" | "RunAuthorizer.revokeByJti" | "RunCharge.close" | "ArtifactRegistry.sync" | "UsageRecorder.record";
|
|
32
|
+
export type NoticeName = "RunAuthorizer.revoke" | "RunAuthorizer.revokeByJti" | "RunCharge.close" | "ArtifactRegistry.sync" | "UsageRecorder.record" | "notifyDataProfileSettled";
|
|
33
33
|
export type GateRefusal = {
|
|
34
34
|
readonly kind: "failed";
|
|
35
35
|
readonly gate: GateName;
|
package/dist/lib/metrics.d.ts
CHANGED
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
* on the no-op provider for the life of the process.
|
|
33
33
|
*/
|
|
34
34
|
import type { StepExecutionStatus } from "../state/schema.js";
|
|
35
|
-
/** Terminal status of a run
|
|
36
|
-
export type RunOutcome = "completed" | "partial" | "failed" | "canceled";
|
|
35
|
+
/** Terminal status of a run, the same as the run ledger. */
|
|
36
|
+
export type RunOutcome = "completed" | "partial" | "failed" | "canceled" | "suspended_insufficient_funds";
|
|
37
37
|
/** The workflow family a run belongs to. */
|
|
38
38
|
export type RunWorkflow = "analysis" | "data_profile";
|
|
39
39
|
/** Terminal status of an executed step. A blocker is a failure to deliver, so `blocked` maps here to `failed`. */
|
package/dist/loop/run-agent.js
CHANGED
|
@@ -97,6 +97,7 @@ export function openLoop(agent, initial, session, opts, metricAgentId) {
|
|
|
97
97
|
const source = {
|
|
98
98
|
agentId: session.provenance.agentId ?? agent.id,
|
|
99
99
|
callPath: session.provenance.callPath,
|
|
100
|
+
...(opts.invocationId === undefined ? {} : { invocationId: opts.invocationId }),
|
|
100
101
|
};
|
|
101
102
|
const policy = opts.compaction;
|
|
102
103
|
const viewOptions = { keepFirstTurn: policy?.keepFirstTurn === true };
|
package/dist/loop/types.d.ts
CHANGED
|
@@ -46,6 +46,8 @@ export type RunStep = <T>(name: string, fn: () => Promise<T>) => Promise<T>;
|
|
|
46
46
|
export interface EventSource {
|
|
47
47
|
readonly agentId: string;
|
|
48
48
|
readonly callPath: readonly string[];
|
|
49
|
+
/** The id of the tool call that runs this loop. For a data profile, the workflow id of its attempt. */
|
|
50
|
+
readonly invocationId?: string;
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* Orchestration events the loop emits: iteration boundaries and tool-call
|
|
@@ -16,9 +16,12 @@
|
|
|
16
16
|
import { type ResultAsync } from "neverthrow";
|
|
17
17
|
import type { Pool } from "pg";
|
|
18
18
|
import { type DbError } from "../lib/db-result.js";
|
|
19
|
+
import type { PlanPart } from "../contracts/chat-parts.js";
|
|
20
|
+
import { type PlanRecord } from "../state/index.js";
|
|
19
21
|
export interface PlanCardData {
|
|
20
22
|
id: string;
|
|
21
23
|
planId: string;
|
|
24
|
+
parentPlanId?: string;
|
|
22
25
|
title?: string;
|
|
23
26
|
steps: unknown;
|
|
24
27
|
analytical_narrative: unknown;
|
|
@@ -37,6 +40,14 @@ export interface RunCardData {
|
|
|
37
40
|
title: string;
|
|
38
41
|
stepCount: number;
|
|
39
42
|
}
|
|
43
|
+
/** Build the `data-plan` payload of a stored plan record. `null` when the
|
|
44
|
+
* document no longer parses. An explicit `title` overrides the plan title. */
|
|
45
|
+
export declare function planCardOf(record: PlanRecord, title?: string): PlanCardData | null;
|
|
46
|
+
/** The `data-plan` part of a stored plan record, with the title of the plan. The
|
|
47
|
+
* part schema drops each key that it does not name, thus the part equals the
|
|
48
|
+
* stored card of a transcript. `null` when the document does not parse or the
|
|
49
|
+
* schema refuses the part. */
|
|
50
|
+
export declare function planPartOf(record: PlanRecord): PlanPart | null;
|
|
40
51
|
/** Build the `data-plan` payload by loading the stored plan. `ok(null)` when
|
|
41
52
|
* the plan is missing or no longer parses (absence is NOT an error) — the
|
|
42
53
|
* caller falls back to a chip. */
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
17
|
import { okAsync } from "neverthrow";
|
|
18
18
|
import { tryQuery } from "../lib/db-result.js";
|
|
19
|
+
import { PlanPartSchema } from "../contracts/schemas/chat-parts.js";
|
|
19
20
|
import { AnalysisPlanSchema } from "../schemas/workflow-state.js";
|
|
20
|
-
import { loadPlan } from "../state/index.js";
|
|
21
|
+
import { loadPlan, loadPlanRecord } from "../state/index.js";
|
|
21
22
|
import { parseStructureUrl } from "../contracts/structure-source.js";
|
|
22
23
|
import { normalizeEchartSpec } from "../tools/display/normalize-echart-spec.js";
|
|
23
24
|
import { validatePath } from "../tools/lib/path-validation.js";
|
|
@@ -32,30 +33,43 @@ function presentationId(input) {
|
|
|
32
33
|
.slice(0, 16);
|
|
33
34
|
return `pres-${hash}`;
|
|
34
35
|
}
|
|
36
|
+
/** Build the `data-plan` payload of a stored plan record. `null` when the
|
|
37
|
+
* document no longer parses. An explicit `title` overrides the plan title. */
|
|
38
|
+
export function planCardOf(record, title) {
|
|
39
|
+
const parsed = AnalysisPlanSchema.safeParse(record.plan);
|
|
40
|
+
if (!parsed.success)
|
|
41
|
+
return null;
|
|
42
|
+
const id = `pres-${createHash("sha256").update(record.planId).digest("hex").slice(0, 16)}`;
|
|
43
|
+
// Explicit `show_plan({ title })` overrides; otherwise default to the
|
|
44
|
+
// planner-set plan title so both cards share one source.
|
|
45
|
+
const heading = title ?? parsed.data.title;
|
|
46
|
+
return {
|
|
47
|
+
id,
|
|
48
|
+
planId: record.planId,
|
|
49
|
+
...(record.parentPlanId !== null ? { parentPlanId: record.parentPlanId } : {}),
|
|
50
|
+
...(heading !== undefined ? { title: heading } : {}),
|
|
51
|
+
steps: parsed.data.steps,
|
|
52
|
+
analytical_narrative: parsed.data.analytical_narrative,
|
|
53
|
+
omicsType: parsed.data.omicsType,
|
|
54
|
+
omicsSubtype: parsed.data.omicsSubtype,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** The `data-plan` part of a stored plan record, with the title of the plan. The
|
|
58
|
+
* part schema drops each key that it does not name, thus the part equals the
|
|
59
|
+
* stored card of a transcript. `null` when the document does not parse or the
|
|
60
|
+
* schema refuses the part. */
|
|
61
|
+
export function planPartOf(record) {
|
|
62
|
+
const card = planCardOf(record);
|
|
63
|
+
if (!card)
|
|
64
|
+
return null;
|
|
65
|
+
const part = PlanPartSchema.safeParse({ type: "data-plan", ...card });
|
|
66
|
+
return part.success ? part.data : null;
|
|
67
|
+
}
|
|
35
68
|
/** Build the `data-plan` payload by loading the stored plan. `ok(null)` when
|
|
36
69
|
* the plan is missing or no longer parses (absence is NOT an error) — the
|
|
37
70
|
* caller falls back to a chip. */
|
|
38
71
|
export function buildPlanCardData(pool, planId, analysisId, title) {
|
|
39
|
-
return
|
|
40
|
-
if (!plan)
|
|
41
|
-
return null;
|
|
42
|
-
const parsed = AnalysisPlanSchema.safeParse(plan);
|
|
43
|
-
if (!parsed.success)
|
|
44
|
-
return null;
|
|
45
|
-
const id = `pres-${createHash("sha256").update(planId).digest("hex").slice(0, 16)}`;
|
|
46
|
-
// Explicit `show_plan({ title })` overrides; otherwise default to the
|
|
47
|
-
// planner-set plan title so both cards share one source.
|
|
48
|
-
const heading = title ?? parsed.data.title;
|
|
49
|
-
return {
|
|
50
|
-
id,
|
|
51
|
-
planId,
|
|
52
|
-
...(heading !== undefined ? { title: heading } : {}),
|
|
53
|
-
steps: parsed.data.steps,
|
|
54
|
-
analytical_narrative: parsed.data.analytical_narrative,
|
|
55
|
-
omicsType: parsed.data.omicsType,
|
|
56
|
-
omicsSubtype: parsed.data.omicsSubtype,
|
|
57
|
-
};
|
|
58
|
-
});
|
|
72
|
+
return loadPlanRecord(pool, planId, { analysisId }).map((record) => (record ? planCardOf(record, title) : null));
|
|
59
73
|
}
|
|
60
74
|
/** Build the `data-run-card` payload for a started analysis run. Loads the
|
|
61
75
|
* plan (for `title` + `stepCount`) the same way `buildPlanCardData` does. The
|
|
@@ -20,6 +20,8 @@ export interface ConversationDisplayRecorderOptions {
|
|
|
20
20
|
readonly sink: EmitFn;
|
|
21
21
|
readonly userMessageId?: string;
|
|
22
22
|
readonly assistantMessageId?: string;
|
|
23
|
+
/** The clock for the times of the sub-agent activity, in milliseconds. The default is the wall clock. */
|
|
24
|
+
readonly now?: () => number;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* Record the display of a turn through the same translation path as a live surface: each event becomes a
|