@inflexa-ai/harness 0.46.2 → 0.48.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 -2
- package/dist/agents/conversation-agent.d.ts +7 -6
- package/dist/agents/conversation-agent.js +26 -4
- package/dist/agents/report-session-agent.d.ts +14 -14
- package/dist/agents/report-session-agent.js +40 -26
- package/dist/agents/sandbox/shared.d.ts +18 -13
- package/dist/agents/sandbox/shared.js +42 -27
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/agents/sandbox-catalog.d.ts +2 -0
- package/dist/agents/sandbox-catalog.js +30 -1
- package/dist/app/synthesize-run.d.ts +10 -6
- package/dist/app/synthesize-run.js +4 -2
- package/dist/contracts/analogy-report.d.ts +46 -2
- package/dist/contracts/analogy-report.js +31 -25
- package/dist/contracts/chat-parts.d.ts +3 -14
- package/dist/contracts/report-reference.d.ts +2 -1
- package/dist/contracts/report-reference.js +2 -1
- package/dist/contracts/schemas/chat-parts.d.ts +0 -27
- package/dist/contracts/schemas/chat-parts.js +1 -3
- package/dist/execution/run-canceler.d.ts +2 -0
- package/dist/execution/run-canceler.js +9 -0
- package/dist/execution/run-synthesis.d.ts +36 -8
- package/dist/execution/run-synthesis.js +114 -32
- package/dist/index.d.ts +5 -6
- package/dist/index.js +5 -7
- package/dist/input-scan/enrich.d.ts +5 -10
- package/dist/input-scan/enrich.js +12 -8
- package/dist/lib/hooks.d.ts +1 -1
- package/dist/lib/markdown-pdf.d.ts +27 -0
- package/dist/lib/markdown-pdf.js +236 -0
- package/dist/lib/metrics.d.ts +31 -0
- package/dist/lib/metrics.js +64 -0
- package/dist/lib/pdf-text.d.ts +23 -0
- package/dist/lib/pdf-text.js +34 -0
- package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +3 -5
- package/dist/lib/regulatory-corpus/fetch-ich.js +3 -5
- package/dist/loop/chat-stream.js +2 -1
- package/dist/loop/run-loop.d.ts +5 -0
- package/dist/loop/run-loop.js +30 -2
- package/dist/loop/tool-name-repair.d.ts +11 -0
- package/dist/loop/tool-name-repair.js +23 -0
- package/dist/loop/types.d.ts +19 -0
- package/dist/memory/card-builders.d.ts +1 -1
- package/dist/prompts/SOUL.d.ts +6 -6
- package/dist/prompts/SOUL.js +22 -121
- package/dist/prompts/analogical-reasoner.d.ts +1 -1
- package/dist/prompts/analogical-reasoner.js +35 -101
- package/dist/prompts/briefing.d.ts +20 -11
- package/dist/prompts/briefing.js +36 -19
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +103 -383
- package/dist/prompts/planner.d.ts +1 -5
- package/dist/prompts/planner.js +45 -128
- package/dist/prompts/report-session.d.ts +1 -1
- package/dist/prompts/report-session.js +29 -58
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +3 -3
- package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/cheminformatics-agent.js +12 -47
- package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
- package/dist/prompts/sandbox/chromatin-agent.js +4 -5
- package/dist/prompts/sandbox/data-profiler.js +11 -34
- package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
- package/dist/prompts/sandbox/dna-methylation-agent.js +3 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +23 -73
- package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
- package/dist/prompts/sandbox/enrichment-agent.js +3 -1
- package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
- package/dist/prompts/sandbox/genomic-variant-agent.js +3 -4
- package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/immune-profiling-agent.js +5 -4
- package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/metabolomics-agent.js +3 -1
- package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
- package/dist/prompts/sandbox/microbiome-agent.js +3 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +3 -1
- package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multimodal-sc-agent.js +3 -1
- package/dist/prompts/sandbox/network-agent.d.ts +1 -1
- package/dist/prompts/sandbox/network-agent.js +3 -1
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +4 -7
- package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/proteomics-agent.js +3 -1
- package/dist/prompts/sandbox/scientific-executor.d.ts +1 -1
- package/dist/prompts/sandbox/scientific-executor.js +0 -12
- package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
- package/dist/prompts/sandbox/single-cell-agent.js +3 -1
- package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/spatial-omics-agent.js +3 -1
- package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/statistical-modeling-agent.js +4 -4
- package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.js +10 -29
- package/dist/prompts/sandbox-standards.d.ts +15 -18
- package/dist/prompts/sandbox-standards.js +96 -305
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +24 -90
- package/dist/provenance/collector.d.ts +2 -5
- package/dist/provenance/collector.js +2 -5
- package/dist/provenance/seam.d.ts +36 -1
- package/dist/provenance/workspace-reads.d.ts +36 -0
- package/dist/provenance/workspace-reads.js +33 -0
- package/dist/report-model/production-resolver.d.ts +22 -52
- package/dist/report-model/production-resolver.js +43 -112
- package/dist/report-render/chart-export.d.ts +9 -0
- package/dist/report-render/chart-export.js +1 -1
- package/dist/report-render/views/chart-view.d.ts +1 -0
- package/dist/report-render/views/chart-view.js +1 -0
- package/dist/report-render/views/lineage.d.ts +1 -0
- package/dist/report-render/views/page-view.d.ts +1 -0
- package/dist/report-render/views/page-view.js +1 -0
- package/dist/report-render/views/prose.d.ts +1 -0
- package/dist/report-render/views/prose.js +1 -0
- package/dist/report-render/views/references-view.d.ts +1 -0
- package/dist/report-render/views/values.d.ts +1 -0
- package/dist/report-render/views/values.js +1 -0
- package/dist/runtime/assemble.d.ts +32 -12
- package/dist/runtime/assemble.js +49 -38
- package/dist/sandbox/client.d.ts +5 -3
- package/dist/sandbox/create-sandbox.d.ts +7 -12
- package/dist/sandbox/create-sandbox.js +15 -37
- package/dist/sandbox/docker-client.d.ts +1 -3
- package/dist/sandbox/docker-client.js +3 -5
- package/dist/sandbox/exec-outcome.d.ts +11 -11
- package/dist/sandbox/exec-outcome.js +22 -22
- package/dist/sandbox/exec.d.ts +5 -0
- package/dist/sandbox/exec.js +9 -1
- package/dist/sandbox/identity.d.ts +4 -16
- package/dist/sandbox/identity.js +5 -21
- package/dist/sandbox/k8s-client.d.ts +0 -1
- package/dist/sandbox/k8s-client.js +8 -13
- package/dist/sandbox/lease-names.d.ts +6 -0
- package/dist/sandbox/lease-names.js +12 -0
- package/dist/sandbox/leases.d.ts +105 -0
- package/dist/sandbox/leases.js +519 -0
- package/dist/sandbox/liveness.d.ts +5 -2
- package/dist/sandbox/mount-plan.d.ts +10 -1
- package/dist/sandbox/mount-plan.js +7 -1
- package/dist/sandbox/reconciler.d.ts +58 -0
- package/dist/sandbox/reconciler.js +153 -0
- package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
- package/dist/sandbox/types.d.ts +25 -18
- package/dist/sandbox/types.js +10 -4
- package/dist/schemas/plan-schemas.d.ts +0 -21
- package/dist/schemas/plan-schemas.js +2 -3
- package/dist/schemas/run-synthesis.d.ts +2 -2
- package/dist/schemas/run-synthesis.js +3 -3
- package/dist/schemas/validate-plan.d.ts +1 -14
- package/dist/schemas/validate-plan.js +5 -24
- package/dist/schemas/workflow-state.d.ts +3 -32
- package/dist/schemas/workflow-state.js +4 -13
- package/dist/state/index.d.ts +2 -3
- package/dist/state/index.js +1 -2
- package/dist/state/migrations/20261030120000_lease_the_sandboxes.d.ts +7 -0
- package/dist/state/migrations/20261030120000_lease_the_sandboxes.js +34 -0
- package/dist/state/migrations/20261030120100_drop_the_report_derivations.d.ts +5 -0
- package/dist/state/migrations/20261030120100_drop_the_report_derivations.js +9 -0
- package/dist/state/migrations/20261030120200_keep_the_report_derivations.d.ts +6 -0
- package/dist/state/migrations/20261030120200_keep_the_report_derivations.js +10 -0
- package/dist/state/migrations/index.js +6 -0
- package/dist/state/purge-analysis.d.ts +4 -2
- package/dist/state/purge-analysis.js +22 -11
- package/dist/state/sandbox-leases.d.ts +81 -0
- package/dist/state/sandbox-leases.js +247 -0
- package/dist/state/schema.d.ts +1 -13
- package/dist/state/schema.js +1 -6
- package/dist/state/step-executions.d.ts +13 -2
- package/dist/state/step-executions.js +23 -4
- package/dist/tasks/data-profile.d.ts +40 -2
- package/dist/tasks/data-profile.js +89 -87
- package/dist/tools/ad-hoc-router.d.ts +1 -6
- package/dist/tools/ad-hoc-router.js +5 -48
- package/dist/tools/bio/comptox.js +1 -1
- package/dist/tools/bio/drug-gene-interactions.js +1 -1
- package/dist/tools/bio/gene-disease-evidence.js +1 -1
- package/dist/tools/bio/keys.d.ts +1 -1
- package/dist/tools/bio/pubmed.js +31 -0
- package/dist/tools/bio/search-gene.js +17 -0
- package/dist/tools/bio/search-geo-datasets.js +13 -0
- package/dist/tools/bio/search-regulatory-approvals.js +1 -1
- package/dist/tools/define-tool.d.ts +25 -2
- package/dist/tools/define-tool.js +11 -1
- package/dist/tools/display/show-user.js +1 -1
- package/dist/tools/execute-analysis.d.ts +1 -3
- package/dist/tools/execute-analysis.js +5 -33
- package/dist/tools/report-authoring/authoring-tools.d.ts +2 -2
- package/dist/tools/report-authoring/authoring-tools.js +31 -6
- package/dist/tools/report-session/index.d.ts +0 -1
- package/dist/tools/report-session/index.js +0 -1
- package/dist/tools/report-session/script-tools.d.ts +33 -0
- package/dist/tools/report-session/script-tools.js +186 -0
- package/dist/tools/research/generate-analogy-report.d.ts +16 -9
- package/dist/tools/research/generate-analogy-report.js +111 -49
- package/dist/tools/research/generate-plan.d.ts +102 -7
- package/dist/tools/research/generate-plan.js +74 -43
- package/dist/tools/research/index.d.ts +4 -3
- package/dist/tools/research/index.js +4 -3
- package/dist/tools/research/inspect-run.d.ts +0 -1
- package/dist/tools/research/inspect-run.js +5 -10
- package/dist/tools/research/search-arxiv.js +15 -0
- package/dist/tools/research/search-github-repos.js +13 -0
- package/dist/tools/research/search-semantic-scholar.js +16 -0
- package/dist/tools/research/synthesis-lookups.d.ts +21 -0
- package/dist/tools/research/synthesis-lookups.js +29 -0
- package/dist/tools/research/web-fetch.d.ts +1 -1
- package/dist/tools/research/web-fetch.js +14 -12
- package/dist/tools/sandbox/lease-tools.d.ts +32 -0
- package/dist/tools/sandbox/lease-tools.js +60 -0
- package/dist/tools/script/archive.d.ts +34 -0
- package/dist/tools/script/archive.js +182 -0
- package/dist/tools/script/codemode-worker.d.ts +5 -0
- package/dist/tools/script/codemode-worker.js +5 -0
- package/dist/tools/script/file-tools.d.ts +106 -0
- package/dist/tools/script/file-tools.js +491 -0
- package/dist/tools/script/metrics.d.ts +30 -0
- package/dist/tools/script/metrics.js +53 -0
- package/dist/tools/script/quickjs.wasm +0 -0
- package/dist/tools/script/run-script.d.ts +76 -0
- package/dist/tools/script/run-script.js +413 -0
- package/dist/tools/script/scratch.d.ts +84 -0
- package/dist/tools/script/scratch.js +145 -0
- package/dist/tools/start-report-session.js +1 -1
- package/dist/tools/workspace/edit-file.js +2 -1
- package/dist/tools/workspace/execute-command.d.ts +9 -13
- package/dist/tools/workspace/execute-command.js +23 -19
- package/dist/tools/workspace/file-stat.js +1 -1
- package/dist/tools/workspace/grep.d.ts +5 -2
- package/dist/tools/workspace/grep.js +19 -10
- package/dist/tools/workspace/mutator.d.ts +51 -4
- package/dist/tools/workspace/mutator.js +54 -13
- package/dist/tools/workspace/read-file.d.ts +5 -2
- package/dist/tools/workspace/read-file.js +15 -11
- package/dist/tools/workspace/read-surface.d.ts +17 -0
- package/dist/tools/workspace/read-surface.js +17 -0
- package/dist/tools/workspace/result-bounds.d.ts +1 -0
- package/dist/tools/workspace/run-exec.d.ts +12 -13
- package/dist/tools/workspace/run-exec.js +13 -13
- package/dist/tools/workspace/scan-inputs.d.ts +2 -5
- package/dist/tools/workspace/scan-inputs.js +2 -3
- package/dist/tools/workspace/show-file.js +1 -1
- package/dist/tools/workspace/show-plan.js +4 -3
- package/dist/tools/workspace/write-file.js +2 -1
- package/dist/workflows/execute-analysis-scheduler.d.ts +0 -26
- package/dist/workflows/execute-analysis-scheduler.js +12 -32
- package/dist/workflows/execute-analysis.d.ts +17 -35
- package/dist/workflows/execute-analysis.js +13 -107
- package/dist/workflows/pause.js +29 -22
- package/dist/workflows/sandbox-step.d.ts +16 -31
- package/dist/workflows/sandbox-step.js +36 -71
- package/dist/workflows/test/sql-writes.d.ts +0 -1
- package/dist/workflows/test/sql-writes.js +0 -2
- package/dist/workspace/filesystem.d.ts +2 -2
- package/dist/workspace/filesystem.js +10 -5
- package/dist/workspace/paths.d.ts +19 -1
- package/dist/workspace/paths.js +22 -1
- package/dist/workspace/session-files.d.ts +35 -0
- package/dist/workspace/session-files.js +16 -0
- package/package.json +7 -3
- package/dist/prompts/literature-reviewer.d.ts +0 -1
- package/dist/prompts/literature-reviewer.js +0 -114
- package/dist/sandbox/reaper.d.ts +0 -81
- package/dist/sandbox/reaper.js +0 -161
- package/dist/sandbox/step-sandbox.d.ts +0 -47
- package/dist/sandbox/step-sandbox.js +0 -53
- package/dist/state/active-sandboxes.d.ts +0 -33
- package/dist/state/active-sandboxes.js +0 -65
- package/dist/tasks/extract-values-script.d.ts +0 -64
- package/dist/tasks/extract-values-script.js +0 -180
- package/dist/tasks/extract-values.d.ts +0 -77
- package/dist/tasks/extract-values.js +0 -146
- package/dist/tools/report-session/derive-table.d.ts +0 -164
- package/dist/tools/report-session/derive-table.js +0 -419
- package/dist/tools/research/literature-reviewer.d.ts +0 -42
- package/dist/tools/research/literature-reviewer.js +0 -107
- package/dist/workflows/metrics.d.ts +0 -23
- package/dist/workflows/metrics.js +0 -38
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entries of a compressed file, for the read tools of a script: a zip, a tar, a gzip-compressed tar, or one
|
|
3
|
+
* gzip-compressed file.
|
|
4
|
+
*
|
|
5
|
+
* Each read runs on the host and holds the bytes in memory, thus each one has a cap. A zip names the size of each
|
|
6
|
+
* entry in its index, thus a list reads no entry and a read decompresses one entry. A tar has no index, thus a list
|
|
7
|
+
* and a read of a `.tar.gz` decompress the whole stream, up to {@link ARCHIVE_SCAN_CAP_BYTES}.
|
|
8
|
+
*/
|
|
9
|
+
import { type Result } from "neverthrow";
|
|
10
|
+
export type ArchiveKind = "zip" | "tar" | "tar-gzip" | "gzip";
|
|
11
|
+
/** The cap of the decompressed stream of a gzip-compressed tar or file that a list or a read decompresses. */
|
|
12
|
+
export declare const ARCHIVE_SCAN_CAP_BYTES: number;
|
|
13
|
+
export type ArchiveEntry = {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly bytes: number;
|
|
16
|
+
};
|
|
17
|
+
/** Why an entry did not read. `too_large` carries the size of the entry, when the archive names it. */
|
|
18
|
+
export type EntryRefusal = {
|
|
19
|
+
readonly kind: "not_found";
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: "too_large";
|
|
22
|
+
readonly bytes: number | undefined;
|
|
23
|
+
} | {
|
|
24
|
+
readonly kind: "unparsable";
|
|
25
|
+
readonly detail: string;
|
|
26
|
+
};
|
|
27
|
+
/** The kind of a compressed file by its name, or `undefined` for a file that is not one. */
|
|
28
|
+
export declare function archiveKindOf(path: string): ArchiveKind | undefined;
|
|
29
|
+
/** The one entry of a gzip-compressed file: its name with no `.gz`. */
|
|
30
|
+
export declare function gzipEntryName(path: string): string;
|
|
31
|
+
/** Each file of a compressed file, with its decompressed size. */
|
|
32
|
+
export declare function listArchive(kind: ArchiveKind, path: string, content: Buffer): Result<ArchiveEntry[], EntryRefusal>;
|
|
33
|
+
/** The decompressed bytes of one entry, up to `cap`. */
|
|
34
|
+
export declare function readArchiveEntry(kind: ArchiveKind, path: string, content: Buffer, entry: string, cap: number): Result<Buffer, EntryRefusal>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entries of a compressed file, for the read tools of a script: a zip, a tar, a gzip-compressed tar, or one
|
|
3
|
+
* gzip-compressed file.
|
|
4
|
+
*
|
|
5
|
+
* Each read runs on the host and holds the bytes in memory, thus each one has a cap. A zip names the size of each
|
|
6
|
+
* entry in its index, thus a list reads no entry and a read decompresses one entry. A tar has no index, thus a list
|
|
7
|
+
* and a read of a `.tar.gz` decompress the whole stream, up to {@link ARCHIVE_SCAN_CAP_BYTES}.
|
|
8
|
+
*/
|
|
9
|
+
import { basename } from "node:path";
|
|
10
|
+
import { gunzipSync } from "node:zlib";
|
|
11
|
+
import { unzipSync } from "fflate";
|
|
12
|
+
import { err, ok } from "neverthrow";
|
|
13
|
+
/** The cap of the decompressed stream of a gzip-compressed tar or file that a list or a read decompresses. */
|
|
14
|
+
export const ARCHIVE_SCAN_CAP_BYTES = 64 * 1024 * 1024;
|
|
15
|
+
/** The kind of a compressed file by its name, or `undefined` for a file that is not one. */
|
|
16
|
+
export function archiveKindOf(path) {
|
|
17
|
+
const lower = path.toLowerCase();
|
|
18
|
+
if (lower.endsWith(".zip"))
|
|
19
|
+
return "zip";
|
|
20
|
+
if (lower.endsWith(".tar"))
|
|
21
|
+
return "tar";
|
|
22
|
+
if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz"))
|
|
23
|
+
return "tar-gzip";
|
|
24
|
+
if (lower.endsWith(".gz"))
|
|
25
|
+
return "gzip";
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
/** The one entry of a gzip-compressed file: its name with no `.gz`. */
|
|
29
|
+
export function gzipEntryName(path) {
|
|
30
|
+
return basename(path).slice(0, -".gz".length);
|
|
31
|
+
}
|
|
32
|
+
/** The decompressed bytes of a gzip stream, or `too_large` past `cap`. */
|
|
33
|
+
function gunzip(content, cap) {
|
|
34
|
+
try {
|
|
35
|
+
return ok(gunzipSync(content, { maxOutputLength: cap }));
|
|
36
|
+
}
|
|
37
|
+
catch (cause) {
|
|
38
|
+
if (cause instanceof RangeError)
|
|
39
|
+
return err({ kind: "too_large", bytes: undefined });
|
|
40
|
+
return err({ kind: "unparsable", detail: "the gzip stream is damaged" });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const TAR_BLOCK = 512;
|
|
44
|
+
/** One text field of a tar header: the bytes up to the first NUL. */
|
|
45
|
+
function tarText(block, start, length) {
|
|
46
|
+
const field = block.subarray(start, start + length);
|
|
47
|
+
const end = field.indexOf(0);
|
|
48
|
+
return field.subarray(0, end === -1 ? field.length : end).toString("utf8");
|
|
49
|
+
}
|
|
50
|
+
/** The `path` record of a pax extended header, which names an entry longer than the header field holds. */
|
|
51
|
+
function paxPath(data) {
|
|
52
|
+
for (const line of data.toString("utf8").split("\n")) {
|
|
53
|
+
const record = line.slice(line.indexOf(" ") + 1);
|
|
54
|
+
if (record.startsWith("path="))
|
|
55
|
+
return record.slice("path=".length);
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Each regular file of a tar, with its data. A GNU long name and a pax `path` record rename the entry that follows
|
|
61
|
+
* them. A directory, a link, and each other special entry is no file, thus it is skipped.
|
|
62
|
+
*/
|
|
63
|
+
function tarFiles(tar) {
|
|
64
|
+
const files = [];
|
|
65
|
+
let offset = 0;
|
|
66
|
+
let longName;
|
|
67
|
+
while (offset + TAR_BLOCK <= tar.length) {
|
|
68
|
+
const header = tar.subarray(offset, offset + TAR_BLOCK);
|
|
69
|
+
if (header.every((byte) => byte === 0))
|
|
70
|
+
break;
|
|
71
|
+
const size = Number.parseInt(tarText(header, 124, 12).trim() || "0", 8);
|
|
72
|
+
if (!Number.isSafeInteger(size) || size < 0)
|
|
73
|
+
return err({ kind: "unparsable", detail: "a tar header has no valid size" });
|
|
74
|
+
const dataStart = offset + TAR_BLOCK;
|
|
75
|
+
if (dataStart + size > tar.length)
|
|
76
|
+
return err({ kind: "unparsable", detail: "the tar ends inside an entry" });
|
|
77
|
+
const data = tar.subarray(dataStart, dataStart + size);
|
|
78
|
+
const type = String.fromCharCode(header[156] ?? 0);
|
|
79
|
+
const prefix = tarText(header, 257, 6) === "ustar" ? tarText(header, 345, 155) : "";
|
|
80
|
+
const name = longName ?? (prefix === "" ? tarText(header, 0, 100) : `${prefix}/${tarText(header, 0, 100)}`);
|
|
81
|
+
if (type === "L")
|
|
82
|
+
longName = tarText(data, 0, data.length);
|
|
83
|
+
else if (type === "x")
|
|
84
|
+
longName = paxPath(data) ?? longName;
|
|
85
|
+
else {
|
|
86
|
+
longName = undefined;
|
|
87
|
+
if (type === "0" || type === "\0")
|
|
88
|
+
files.push({ name, data });
|
|
89
|
+
}
|
|
90
|
+
offset = dataStart + Math.ceil(size / TAR_BLOCK) * TAR_BLOCK;
|
|
91
|
+
}
|
|
92
|
+
return ok(files);
|
|
93
|
+
}
|
|
94
|
+
/** The tar inside a tar archive: the bytes themselves, or the decompressed stream of a `.tar.gz`. */
|
|
95
|
+
function tarOf(kind, content) {
|
|
96
|
+
return kind === "tar" ? ok(content) : gunzip(content, ARCHIVE_SCAN_CAP_BYTES);
|
|
97
|
+
}
|
|
98
|
+
/** The files of a zip, as its index names them. A directory entry is no file. */
|
|
99
|
+
function zipIndex(content) {
|
|
100
|
+
const entries = [];
|
|
101
|
+
try {
|
|
102
|
+
unzipSync(content, {
|
|
103
|
+
filter: (file) => {
|
|
104
|
+
if (!file.name.endsWith("/"))
|
|
105
|
+
entries.push({ name: file.name, bytes: file.originalSize });
|
|
106
|
+
return false;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return err({ kind: "unparsable", detail: "the zip is damaged" });
|
|
112
|
+
}
|
|
113
|
+
return ok(entries);
|
|
114
|
+
}
|
|
115
|
+
/** Each file of a compressed file, with its decompressed size. */
|
|
116
|
+
export function listArchive(kind, path, content) {
|
|
117
|
+
switch (kind) {
|
|
118
|
+
case "zip":
|
|
119
|
+
return zipIndex(content);
|
|
120
|
+
case "gzip": {
|
|
121
|
+
// The last 4 bytes of a gzip stream hold the decompressed size, modulo 2^32.
|
|
122
|
+
const bytes = content.length >= 4 ? content.readUInt32LE(content.length - 4) : 0;
|
|
123
|
+
return ok([{ name: gzipEntryName(path), bytes }]);
|
|
124
|
+
}
|
|
125
|
+
case "tar":
|
|
126
|
+
case "tar-gzip":
|
|
127
|
+
return tarOf(kind, content)
|
|
128
|
+
.andThen(tarFiles)
|
|
129
|
+
.map((files) => files.map((file) => ({ name: file.name, bytes: file.data.length })));
|
|
130
|
+
default: {
|
|
131
|
+
const unhandled = kind;
|
|
132
|
+
throw new Error(`unhandled archive kind: ${String(unhandled)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** The decompressed bytes of one entry, up to `cap`. */
|
|
137
|
+
export function readArchiveEntry(kind, path, content, entry, cap) {
|
|
138
|
+
switch (kind) {
|
|
139
|
+
case "zip": {
|
|
140
|
+
const index = zipIndex(content);
|
|
141
|
+
if (index.isErr())
|
|
142
|
+
return err(index.error);
|
|
143
|
+
const found = index.value.find((file) => file.name === entry);
|
|
144
|
+
if (found === undefined)
|
|
145
|
+
return err({ kind: "not_found" });
|
|
146
|
+
if (found.bytes > cap)
|
|
147
|
+
return err({ kind: "too_large", bytes: found.bytes });
|
|
148
|
+
try {
|
|
149
|
+
const data = unzipSync(content, { filter: (file) => file.name === entry })[entry];
|
|
150
|
+
if (data === undefined)
|
|
151
|
+
return err({ kind: "not_found" });
|
|
152
|
+
// The index can lie about the size, thus the cap holds on the bytes too.
|
|
153
|
+
if (data.length > cap)
|
|
154
|
+
return err({ kind: "too_large", bytes: data.length });
|
|
155
|
+
return ok(Buffer.from(data.buffer, data.byteOffset, data.length));
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return err({ kind: "unparsable", detail: `the entry ${entry} did not decompress` });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
case "gzip":
|
|
162
|
+
if (entry !== gzipEntryName(path))
|
|
163
|
+
return err({ kind: "not_found" });
|
|
164
|
+
return gunzip(content, cap);
|
|
165
|
+
case "tar":
|
|
166
|
+
case "tar-gzip": {
|
|
167
|
+
const files = tarOf(kind, content).andThen(tarFiles);
|
|
168
|
+
if (files.isErr())
|
|
169
|
+
return err(files.error);
|
|
170
|
+
const found = files.value.find((file) => file.name === entry);
|
|
171
|
+
if (found === undefined)
|
|
172
|
+
return err({ kind: "not_found" });
|
|
173
|
+
if (found.data.length > cap)
|
|
174
|
+
return err({ kind: "too_large", bytes: found.data.length });
|
|
175
|
+
return ok(found.data);
|
|
176
|
+
}
|
|
177
|
+
default: {
|
|
178
|
+
const unhandled = kind;
|
|
179
|
+
throw new Error(`unhandled archive kind: ${String(unhandled)}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entry of the worker thread of `run_script`. An embedder that bundles the harness, for example a Bun single-file
|
|
3
|
+
* binary, adds this module as an entry of its build, and gives its embedded path as `ScriptRuntime.workerUrl`.
|
|
4
|
+
*/
|
|
5
|
+
import "@earendil-works/pi-codemode/worker";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entry of the worker thread of `run_script`. An embedder that bundles the harness, for example a Bun single-file
|
|
3
|
+
* binary, adds this module as an entry of its build, and gives its embedded path as `ScriptRuntime.workerUrl`.
|
|
4
|
+
*/
|
|
5
|
+
import "@earendil-works/pi-codemode/worker";
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file tools of a script: `read_table`, `read_pdf`, `write_derived`, `render_chart`, and `export_pdf`.
|
|
3
|
+
*
|
|
4
|
+
* The VM of `run_script` has no file system. These tools are its only reach into the workspace, thus each one is
|
|
5
|
+
* the boundary. `read_table` reads through the read seam of the workspace, which confines a path to the analysis
|
|
6
|
+
* of the call and refuses a symbolic link. `write_derived` and `render_chart` write only into the `derived/`
|
|
7
|
+
* directory of the scratch of the session.
|
|
8
|
+
*
|
|
9
|
+
* A table read holds at most 16 MiB, and the parse runs on the host. A larger table, or a format with no parser
|
|
10
|
+
* here, is work for an analysis run, and the refusal says so. `list_archive` lists the files of a compressed file, and
|
|
11
|
+
* a read names one of them as its `entry`. A gzip-compressed table reads with no entry.
|
|
12
|
+
*
|
|
13
|
+
* Each tool gives the files that it read or wrote as its call record. `run_script` collects the records of the
|
|
14
|
+
* calls of one script, thus the provenance of the script chains each derived file to the tables that it read.
|
|
15
|
+
*/
|
|
16
|
+
import { type Result } from "neverthrow";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import type { AgentSession } from "../../auth/types.js";
|
|
19
|
+
import { type Row } from "../../report-model/production-resolver.js";
|
|
20
|
+
import type { WorkspaceReadLineage } from "../../provenance/workspace-reads.js";
|
|
21
|
+
import type { WorkspaceFilesystem } from "../../workspace/filesystem.js";
|
|
22
|
+
import { type ResolveWorkspaceRoot } from "../../workspace/paths.js";
|
|
23
|
+
import { type Tool, type WithToolCallRecord } from "../define-tool.js";
|
|
24
|
+
import type { ScratchFile, ScriptRead, ScriptScratch } from "./scratch.js";
|
|
25
|
+
/** The cap of one table read. It matches the cap of the report path, which reads with the same parsers. */
|
|
26
|
+
export declare const TABLE_READ_CAP_BYTES: number;
|
|
27
|
+
/** What one call of a file tool did to files. `run_script` reads it from the call record of a nested call. */
|
|
28
|
+
export type ScriptFileEffect = {
|
|
29
|
+
readonly reads?: readonly ScriptRead[];
|
|
30
|
+
readonly writes?: readonly ScratchFile[];
|
|
31
|
+
};
|
|
32
|
+
export declare const ScriptFileEffectSchema: z.ZodObject<{
|
|
33
|
+
reads: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
34
|
+
path: z.ZodString;
|
|
35
|
+
hash: z.ZodString;
|
|
36
|
+
}, z.core.$strip>>>;
|
|
37
|
+
writes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
38
|
+
path: z.ZodString;
|
|
39
|
+
hash: z.ZodString;
|
|
40
|
+
size: z.ZodNumber;
|
|
41
|
+
}, z.core.$strip>>>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export type ScriptFileToolsDeps = {
|
|
44
|
+
readonly workspaceFs: WorkspaceFilesystem;
|
|
45
|
+
readonly resolveWorkspaceRoot: ResolveWorkspaceRoot;
|
|
46
|
+
readonly scratch: ScriptScratch;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The rows of one table, the columns that they keep, and the bytes of the file on disk that held them. A read of an
|
|
50
|
+
* entry names the compressed file, thus its hash is the hash of that file.
|
|
51
|
+
*/
|
|
52
|
+
export type TableRows = {
|
|
53
|
+
readonly source: Buffer;
|
|
54
|
+
readonly columns: string[];
|
|
55
|
+
readonly rows: Row[];
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Read one table through the read seam, parse it on the host, and keep the named columns. A refusal is the line
|
|
59
|
+
* that the script reads. `tooLarge` names where a table over the cap goes instead.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readTableRows(args: {
|
|
62
|
+
readonly workspaceFs: WorkspaceFilesystem;
|
|
63
|
+
readonly session: AgentSession;
|
|
64
|
+
readonly path: string;
|
|
65
|
+
readonly entry?: string;
|
|
66
|
+
readonly columns: readonly string[] | undefined;
|
|
67
|
+
readonly tooLarge: string;
|
|
68
|
+
}): Promise<Result<TableRows, string>>;
|
|
69
|
+
export declare const ReadTableOutputSchema: z.ZodObject<{
|
|
70
|
+
path: z.ZodString;
|
|
71
|
+
columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
72
|
+
rowCount: z.ZodNumber;
|
|
73
|
+
rows: z.ZodReadonly<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
declare const readPdfInput: z.ZodObject<{
|
|
76
|
+
path: z.ZodString;
|
|
77
|
+
entry: z.ZodOptional<z.ZodString>;
|
|
78
|
+
firstPage: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
lastPage: z.ZodOptional<z.ZodNumber>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
declare const ReadPdfOutputSchema: z.ZodObject<{
|
|
82
|
+
path: z.ZodString;
|
|
83
|
+
totalPages: z.ZodNumber;
|
|
84
|
+
pages: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
85
|
+
page: z.ZodNumber;
|
|
86
|
+
text: z.ZodString;
|
|
87
|
+
}, z.core.$strip>>>;
|
|
88
|
+
}, z.core.$strip>;
|
|
89
|
+
type ReadPdfOutput = WithToolCallRecord<z.infer<typeof ReadPdfOutputSchema>, ScriptFileEffect>;
|
|
90
|
+
/** `lineage` records each read in the lineage of a step. */
|
|
91
|
+
export declare function createReadPdfTool(deps: Pick<ScriptFileToolsDeps, "workspaceFs" | "resolveWorkspaceRoot"> & {
|
|
92
|
+
readonly lineage?: WorkspaceReadLineage;
|
|
93
|
+
}): Tool<z.infer<typeof readPdfInput>, ReadPdfOutput>;
|
|
94
|
+
export type Cell = string | number | boolean | null;
|
|
95
|
+
/** The text of `rows` in the format that the extension of `name` names, or `undefined` for another extension. */
|
|
96
|
+
export declare function rowsText(name: string, rows: readonly Record<string, Cell>[]): string | undefined;
|
|
97
|
+
/** What the document tools of a script need. `imageScope` limits the images of a PDF to one directory of a session. */
|
|
98
|
+
export type DocumentToolsDeps = ScriptFileToolsDeps & {
|
|
99
|
+
readonly imageScope?: (session: AgentSession) => string | undefined;
|
|
100
|
+
};
|
|
101
|
+
export declare function createScriptFileTools(deps: ScriptFileToolsDeps): Tool[];
|
|
102
|
+
/** The script tools that read a table, a PDF, and the files of a compressed file of the workspace, and write nothing. */
|
|
103
|
+
export declare function createReadScriptTools(deps: Pick<ScriptFileToolsDeps, "workspaceFs" | "resolveWorkspaceRoot">): Tool[];
|
|
104
|
+
/** The tools that make a document in a script: a chart as an SVG file, and a PDF from markdown. */
|
|
105
|
+
export declare function createDocumentTools(deps: DocumentToolsDeps): Tool[];
|
|
106
|
+
export {};
|