@sanity/ailf 2.8.0 → 2.9.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/_vendor/ailf-core/artifact-capture/association.d.ts +35 -0
- package/dist/_vendor/ailf-core/artifact-capture/association.js +28 -0
- package/dist/_vendor/ailf-core/artifact-registry.d.ts +124 -23
- package/dist/_vendor/ailf-core/artifact-registry.js +724 -63
- package/dist/_vendor/ailf-core/index.d.ts +2 -1
- package/dist/_vendor/ailf-core/index.js +2 -1
- package/dist/_vendor/ailf-core/ports/artifact-writer.d.ts +59 -20
- package/dist/_vendor/ailf-core/ports/artifact-writer.js +33 -10
- package/dist/_vendor/ailf-core/ports/context.d.ts +21 -2
- package/dist/_vendor/ailf-core/schemas/pipeline.d.ts +6 -6
- package/dist/_vendor/ailf-core/services/index.d.ts +1 -0
- package/dist/_vendor/ailf-core/services/index.js +1 -0
- package/dist/_vendor/ailf-core/services/slim-report-summary.d.ts +31 -0
- package/dist/_vendor/ailf-core/services/slim-report-summary.js +217 -0
- package/dist/_vendor/ailf-core/types/branded-ids.d.ts +33 -0
- package/dist/_vendor/ailf-core/types/index.d.ts +202 -23
- package/dist/artifact-capture/accumulating-artifact-writer.d.ts +50 -0
- package/dist/artifact-capture/accumulating-artifact-writer.js +111 -0
- package/dist/artifact-capture/api-gateway-artifact-writer.d.ts +17 -4
- package/dist/artifact-capture/api-gateway-artifact-writer.js +58 -7
- package/dist/artifact-capture/emit-file.d.ts +28 -0
- package/dist/artifact-capture/emit-file.js +56 -0
- package/dist/artifact-capture/fanout-artifact-writer.d.ts +39 -0
- package/dist/artifact-capture/fanout-artifact-writer.js +76 -0
- package/dist/artifact-capture/filesystem-collector.d.ts +22 -4
- package/dist/artifact-capture/filesystem-collector.js +48 -23
- package/dist/artifact-capture/gcs-artifact-writer.d.ts +40 -3
- package/dist/artifact-capture/gcs-artifact-writer.js +238 -14
- package/dist/artifact-capture/local-fs-artifact-writer.d.ts +71 -0
- package/dist/artifact-capture/local-fs-artifact-writer.js +273 -0
- package/dist/commands/explain-handler.js +4 -0
- package/dist/commands/pipeline-action.d.ts +5 -0
- package/dist/commands/pipeline-action.js +56 -5
- package/dist/commands/pipeline.d.ts +4 -0
- package/dist/commands/pipeline.js +6 -2
- package/dist/commands/publish.js +4 -1
- package/dist/composition-root.d.ts +13 -10
- package/dist/composition-root.js +74 -20
- package/dist/orchestration/pipeline-orchestrator.d.ts +1 -1
- package/dist/orchestration/pipeline-orchestrator.js +41 -30
- package/dist/orchestration/steps/calculate-scores-step.d.ts +1 -1
- package/dist/orchestration/steps/calculate-scores-step.js +19 -19
- package/dist/orchestration/steps/callback-step.d.ts +1 -1
- package/dist/orchestration/steps/callback-step.js +6 -4
- package/dist/orchestration/steps/compare-step.d.ts +1 -1
- package/dist/orchestration/steps/compare-step.js +4 -2
- package/dist/orchestration/steps/discovery-report-step.d.ts +1 -1
- package/dist/orchestration/steps/discovery-report-step.js +4 -1
- package/dist/orchestration/steps/fetch-docs-step.js +9 -15
- package/dist/orchestration/steps/finalize-run-step.js +21 -7
- package/dist/orchestration/steps/gap-analysis-step.js +34 -6
- package/dist/orchestration/steps/generate-configs-step.d.ts +1 -1
- package/dist/orchestration/steps/generate-configs-step.js +11 -11
- package/dist/orchestration/steps/publish-report-step.d.ts +1 -1
- package/dist/orchestration/steps/publish-report-step.js +24 -19
- package/dist/orchestration/steps/readiness-step.d.ts +1 -1
- package/dist/orchestration/steps/readiness-step.js +4 -1
- package/dist/orchestration/steps/report-step.d.ts +1 -1
- package/dist/orchestration/steps/report-step.js +6 -3
- package/dist/orchestration/steps/run-eval-step.js +14 -9
- package/dist/pipeline/compare.d.ts +2 -2
- package/dist/pipeline/emit-eval-results.d.ts +38 -0
- package/dist/pipeline/emit-eval-results.js +100 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emitFileContents() — reads a file from disk and hands its contents to
|
|
3
|
+
* the writer's `emit()`. Shim for the legacy `captureFile(path)` pattern
|
|
4
|
+
* now that the port takes in-memory payloads.
|
|
5
|
+
*
|
|
6
|
+
* Covers the ~13 producer sites that write a file for user-facing output
|
|
7
|
+
* (e.g. promptfoo writes YAML configs and JSON results) and then need to
|
|
8
|
+
* also capture them as artifacts. Reading at emit-time is uniform, keeps
|
|
9
|
+
* the port narrow, and costs nothing at the sizes in play (all descriptors
|
|
10
|
+
* cap ≤10 MB; most are ≤256 KB).
|
|
11
|
+
*
|
|
12
|
+
* Failures are non-blocking per P5 — a missing file or unparseable JSON
|
|
13
|
+
* returns null + warns rather than throwing, so the pipeline keeps moving
|
|
14
|
+
* even if the user-facing file wasn't produced.
|
|
15
|
+
*
|
|
16
|
+
* See `tasks/plan.md § Q2` for the design rationale.
|
|
17
|
+
*/
|
|
18
|
+
import { promises as fs } from "node:fs";
|
|
19
|
+
import { ARTIFACT_REGISTRY, } from "../_vendor/ailf-core/index.js";
|
|
20
|
+
/**
|
|
21
|
+
* Read a file from disk, parse it per the descriptor's mime, and emit it.
|
|
22
|
+
*
|
|
23
|
+
* - JSON mime: file contents are `JSON.parse`d into an object before `emit()`.
|
|
24
|
+
* - Markdown / YAML mime: file contents are passed to `emit()` as a string.
|
|
25
|
+
* - NDJSON: not supported by `emit()` — use `appendNdjson()` directly instead.
|
|
26
|
+
*
|
|
27
|
+
* Returns null (with a warn) on any error. Never throws.
|
|
28
|
+
*/
|
|
29
|
+
export async function emitFileContents(writer, type, association, filePath) {
|
|
30
|
+
const descriptor = ARTIFACT_REGISTRY[type];
|
|
31
|
+
if (descriptor.mime === "application/x-ndjson") {
|
|
32
|
+
console.warn(` ⚠️ emitFileContents("${type}", ${filePath}): NDJSON types require appendNdjson(), not emit() — skipping`);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
let contents;
|
|
36
|
+
try {
|
|
37
|
+
contents = await fs.readFile(filePath, "utf-8");
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
console.warn(` ⚠️ emitFileContents read failed (non-blocking): ${filePath} — ${message}`);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
let payload = contents;
|
|
45
|
+
if (descriptor.mime === "application/json") {
|
|
46
|
+
try {
|
|
47
|
+
payload = JSON.parse(contents);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
51
|
+
console.warn(` ⚠️ emitFileContents parse failed (non-blocking): ${filePath} — ${message}`);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return writer.emit(type, association, payload);
|
|
56
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FanoutArtifactWriter — layers multiple writers so each `emit()` fans out
|
|
3
|
+
* to every configured backend.
|
|
4
|
+
*
|
|
5
|
+
* D0033 M4 default wiring:
|
|
6
|
+
* `FanoutArtifactWriter([ LocalFilesystemArtifactWriter, GcsArtifactWriter ])`
|
|
7
|
+
*
|
|
8
|
+
* Semantics:
|
|
9
|
+
* - Fan out in declaration order. Every writer runs, even if earlier ones fail.
|
|
10
|
+
* - Return the **first non-null ArtifactRef**. Local is listed first, so a
|
|
11
|
+
* local success + GCS failure still produces a non-null ref pointing at
|
|
12
|
+
* local — the pipeline succeeds and Studio retrieval works against the
|
|
13
|
+
* local tree with a warning logged for the GCS leg.
|
|
14
|
+
* - Failures on individual writers warn (via their own P5 paths) but do
|
|
15
|
+
* not propagate. The fanout never throws.
|
|
16
|
+
*
|
|
17
|
+
* This writer is a composition primitive — it adds no I/O of its own.
|
|
18
|
+
* Tests verify the fanout semantics against `NoOpArtifactWriter` instances
|
|
19
|
+
* plus a recording test double.
|
|
20
|
+
*
|
|
21
|
+
* @see docs/decisions/D0033-unified-run-anchored-artifact-capture.md (§ M4)
|
|
22
|
+
*/
|
|
23
|
+
import type { ArtifactEntry, ArtifactRef, ArtifactType, ArtifactWriter, AssociationValues, RunId, RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
24
|
+
export declare class FanoutArtifactWriter implements ArtifactWriter {
|
|
25
|
+
private readonly writers;
|
|
26
|
+
constructor(writers: readonly ArtifactWriter[]);
|
|
27
|
+
emit<T extends ArtifactType>(type: T, association: AssociationValues, payload: unknown): Promise<ArtifactRef | null>;
|
|
28
|
+
appendNdjson<T extends ArtifactType>(type: T, association: AssociationValues, rows: readonly unknown[]): Promise<ArtifactRef | null>;
|
|
29
|
+
writeManifest(runId: RunId, manifest: RunManifest): Promise<ArtifactRef | null>;
|
|
30
|
+
/** @deprecated Use `emit()` instead. */
|
|
31
|
+
writeBulk(type: ArtifactType, runId: RunId, data: unknown): Promise<ArtifactRef | null>;
|
|
32
|
+
/** @deprecated Use `emit()` per entry instead. */
|
|
33
|
+
writePerEntry(type: ArtifactType, runId: RunId, entries: readonly ArtifactEntry[]): Promise<ArtifactRef | null>;
|
|
34
|
+
/**
|
|
35
|
+
* Run `op` against every delegate writer. Any individual writer's rejected
|
|
36
|
+
* promise is caught and logged; the fanout itself never rejects.
|
|
37
|
+
*/
|
|
38
|
+
private runAll;
|
|
39
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FanoutArtifactWriter — layers multiple writers so each `emit()` fans out
|
|
3
|
+
* to every configured backend.
|
|
4
|
+
*
|
|
5
|
+
* D0033 M4 default wiring:
|
|
6
|
+
* `FanoutArtifactWriter([ LocalFilesystemArtifactWriter, GcsArtifactWriter ])`
|
|
7
|
+
*
|
|
8
|
+
* Semantics:
|
|
9
|
+
* - Fan out in declaration order. Every writer runs, even if earlier ones fail.
|
|
10
|
+
* - Return the **first non-null ArtifactRef**. Local is listed first, so a
|
|
11
|
+
* local success + GCS failure still produces a non-null ref pointing at
|
|
12
|
+
* local — the pipeline succeeds and Studio retrieval works against the
|
|
13
|
+
* local tree with a warning logged for the GCS leg.
|
|
14
|
+
* - Failures on individual writers warn (via their own P5 paths) but do
|
|
15
|
+
* not propagate. The fanout never throws.
|
|
16
|
+
*
|
|
17
|
+
* This writer is a composition primitive — it adds no I/O of its own.
|
|
18
|
+
* Tests verify the fanout semantics against `NoOpArtifactWriter` instances
|
|
19
|
+
* plus a recording test double.
|
|
20
|
+
*
|
|
21
|
+
* @see docs/decisions/D0033-unified-run-anchored-artifact-capture.md (§ M4)
|
|
22
|
+
*/
|
|
23
|
+
export class FanoutArtifactWriter {
|
|
24
|
+
writers;
|
|
25
|
+
constructor(writers) {
|
|
26
|
+
if (writers.length === 0) {
|
|
27
|
+
throw new Error("FanoutArtifactWriter requires at least one delegate writer");
|
|
28
|
+
}
|
|
29
|
+
this.writers = writers;
|
|
30
|
+
}
|
|
31
|
+
async emit(type, association, payload) {
|
|
32
|
+
const refs = await this.runAll((w) => w.emit(type, association, payload));
|
|
33
|
+
return firstNonNull(refs);
|
|
34
|
+
}
|
|
35
|
+
async appendNdjson(type, association, rows) {
|
|
36
|
+
const refs = await this.runAll((w) => w.appendNdjson(type, association, rows));
|
|
37
|
+
return firstNonNull(refs);
|
|
38
|
+
}
|
|
39
|
+
async writeManifest(runId, manifest) {
|
|
40
|
+
const refs = await this.runAll((w) => w.writeManifest(runId, manifest));
|
|
41
|
+
return firstNonNull(refs);
|
|
42
|
+
}
|
|
43
|
+
/** @deprecated Use `emit()` instead. */
|
|
44
|
+
async writeBulk(type, runId, data) {
|
|
45
|
+
const refs = await this.runAll((w) => w.writeBulk(type, runId, data));
|
|
46
|
+
return firstNonNull(refs);
|
|
47
|
+
}
|
|
48
|
+
/** @deprecated Use `emit()` per entry instead. */
|
|
49
|
+
async writePerEntry(type, runId, entries) {
|
|
50
|
+
const refs = await this.runAll((w) => w.writePerEntry(type, runId, entries));
|
|
51
|
+
return firstNonNull(refs);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Run `op` against every delegate writer. Any individual writer's rejected
|
|
55
|
+
* promise is caught and logged; the fanout itself never rejects.
|
|
56
|
+
*/
|
|
57
|
+
async runAll(op) {
|
|
58
|
+
return Promise.all(this.writers.map(async (writer) => {
|
|
59
|
+
try {
|
|
60
|
+
return await op(writer);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
64
|
+
console.warn(` ⚠️ Fanout delegate threw (non-blocking): ${writer.constructor.name} — ${message}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function firstNonNull(refs) {
|
|
71
|
+
for (const ref of refs) {
|
|
72
|
+
if (ref !== null)
|
|
73
|
+
return ref;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* FilesystemArtifactCollector —
|
|
2
|
+
* FilesystemArtifactCollector — DEPRECATED legacy capture path.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* W0050 Slice 5: the unified artifact writer (`ctx.artifactWriter.emit()`)
|
|
5
|
+
* owns artifact production starting this release. This class is retained
|
|
6
|
+
* for one release cycle so producer steps that haven't migrated yet still
|
|
7
|
+
* have a surface to call against; W0052 deletes the class + port.
|
|
8
|
+
*
|
|
9
|
+
* Behavioral changes vs. pre-W0050:
|
|
10
|
+
*
|
|
11
|
+
* - **No tarball.** The `compress` option is ignored; flush() always writes
|
|
12
|
+
* a loose directory tree. The legacy `.tar.gz` artifact archive is no
|
|
13
|
+
* longer produced (D0033 AC8 — "no new capture tarballs").
|
|
14
|
+
* - **First-call deprecation warning.** The first invocation of capture()
|
|
15
|
+
* or captureFile() on any instance emits a one-time-per-process warning
|
|
16
|
+
* pointing callers at `ctx.artifactWriter.emit()`.
|
|
17
|
+
*
|
|
18
|
+
* Everything else (in-memory accumulation, redaction, loose-file output at
|
|
19
|
+
* flush time) is unchanged — existing tests continue to pass. This is the
|
|
20
|
+
* **minimum** pass-through posture. Full delegation to
|
|
21
|
+
* `LocalFilesystemArtifactWriter` is W0052 scope, at which point the port
|
|
22
|
+
* and this class are both deleted.
|
|
7
23
|
*
|
|
8
24
|
* Design principles:
|
|
9
25
|
* - capture() and captureFile() are synchronous (no I/O during step execution)
|
|
10
26
|
* - flush() does all I/O at pipeline end
|
|
11
27
|
* - Failures in capture/captureFile are swallowed (P5: non-blocking)
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Use `ctx.artifactWriter.emit()` instead; removal scheduled for W0052.
|
|
12
30
|
*/
|
|
13
31
|
import type { ArtifactCollector, CaptureFlushResult } from "../_vendor/ailf-core/index.d.ts";
|
|
14
32
|
export interface FilesystemCollectorOptions {
|
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* FilesystemArtifactCollector —
|
|
2
|
+
* FilesystemArtifactCollector — DEPRECATED legacy capture path.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* W0050 Slice 5: the unified artifact writer (`ctx.artifactWriter.emit()`)
|
|
5
|
+
* owns artifact production starting this release. This class is retained
|
|
6
|
+
* for one release cycle so producer steps that haven't migrated yet still
|
|
7
|
+
* have a surface to call against; W0052 deletes the class + port.
|
|
8
|
+
*
|
|
9
|
+
* Behavioral changes vs. pre-W0050:
|
|
10
|
+
*
|
|
11
|
+
* - **No tarball.** The `compress` option is ignored; flush() always writes
|
|
12
|
+
* a loose directory tree. The legacy `.tar.gz` artifact archive is no
|
|
13
|
+
* longer produced (D0033 AC8 — "no new capture tarballs").
|
|
14
|
+
* - **First-call deprecation warning.** The first invocation of capture()
|
|
15
|
+
* or captureFile() on any instance emits a one-time-per-process warning
|
|
16
|
+
* pointing callers at `ctx.artifactWriter.emit()`.
|
|
17
|
+
*
|
|
18
|
+
* Everything else (in-memory accumulation, redaction, loose-file output at
|
|
19
|
+
* flush time) is unchanged — existing tests continue to pass. This is the
|
|
20
|
+
* **minimum** pass-through posture. Full delegation to
|
|
21
|
+
* `LocalFilesystemArtifactWriter` is W0052 scope, at which point the port
|
|
22
|
+
* and this class are both deleted.
|
|
7
23
|
*
|
|
8
24
|
* Design principles:
|
|
9
25
|
* - capture() and captureFile() are synchronous (no I/O during step execution)
|
|
10
26
|
* - flush() does all I/O at pipeline end
|
|
11
27
|
* - Failures in capture/captureFile are swallowed (P5: non-blocking)
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Use `ctx.artifactWriter.emit()` instead; removal scheduled for W0052.
|
|
12
30
|
*/
|
|
13
|
-
import {
|
|
14
|
-
import { copyFileSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
31
|
+
import { copyFileSync, mkdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
|
|
15
32
|
import path from "node:path";
|
|
16
33
|
import { redactArtifactData } from "./redact-artifact.js";
|
|
17
34
|
// ---------------------------------------------------------------------------
|
|
@@ -69,6 +86,17 @@ function fileExtension(format) {
|
|
|
69
86
|
// ---------------------------------------------------------------------------
|
|
70
87
|
// Collector
|
|
71
88
|
// ---------------------------------------------------------------------------
|
|
89
|
+
/**
|
|
90
|
+
* Module-level flag so the W0050 deprecation warning fires exactly once
|
|
91
|
+
* per process even when multiple collectors are constructed.
|
|
92
|
+
*/
|
|
93
|
+
let warnedLegacyCollector = false;
|
|
94
|
+
function warnLegacyCollectorOnce() {
|
|
95
|
+
if (warnedLegacyCollector)
|
|
96
|
+
return;
|
|
97
|
+
warnedLegacyCollector = true;
|
|
98
|
+
console.warn("FilesystemArtifactCollector is deprecated (W0050). Producers should migrate to ctx.artifactWriter.emit(); this class will be removed in W0052.");
|
|
99
|
+
}
|
|
72
100
|
export class FilesystemArtifactCollector {
|
|
73
101
|
enabled = true;
|
|
74
102
|
extrasEnabled;
|
|
@@ -89,6 +117,7 @@ export class FilesystemArtifactCollector {
|
|
|
89
117
|
this.outputDir = path.join(options.captureDir, `${options.mode}-${timestamp}-${shortId}`);
|
|
90
118
|
}
|
|
91
119
|
capture(step, type, data, meta) {
|
|
120
|
+
warnLegacyCollectorOnce();
|
|
92
121
|
try {
|
|
93
122
|
this.entries.push({
|
|
94
123
|
step,
|
|
@@ -103,6 +132,7 @@ export class FilesystemArtifactCollector {
|
|
|
103
132
|
}
|
|
104
133
|
}
|
|
105
134
|
captureFile(step, type, filePath, meta) {
|
|
135
|
+
warnLegacyCollectorOnce();
|
|
106
136
|
try {
|
|
107
137
|
this.entries.push({
|
|
108
138
|
step,
|
|
@@ -208,24 +238,12 @@ export class FilesystemArtifactCollector {
|
|
|
208
238
|
};
|
|
209
239
|
const manifestContent = JSON.stringify(manifest, null, 2);
|
|
210
240
|
writeFileSync(path.join(this.outputDir, "manifest.json"), manifestContent, "utf-8");
|
|
211
|
-
//
|
|
241
|
+
// W0050 Slice 5 — compression disabled unconditionally. The legacy
|
|
242
|
+
// .tar.gz archive is no longer produced (D0033 AC8 "no new capture
|
|
243
|
+
// tarballs"); callers that asked for it get the loose directory plus
|
|
244
|
+
// a one-time warning.
|
|
212
245
|
if (this.options.compress) {
|
|
213
|
-
|
|
214
|
-
const archivePath = `${this.outputDir}.tar.gz`;
|
|
215
|
-
const parentDir = path.dirname(this.outputDir);
|
|
216
|
-
const dirName = path.basename(this.outputDir);
|
|
217
|
-
execFileSync("tar", ["-czf", archivePath, "-C", parentDir, dirName]);
|
|
218
|
-
rmSync(this.outputDir, { recursive: true });
|
|
219
|
-
return {
|
|
220
|
-
artifactCount: manifestEntries.length,
|
|
221
|
-
destination: archivePath,
|
|
222
|
-
totalBytes,
|
|
223
|
-
compressed: true,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
// Non-blocking: compression failed, keep the raw directory
|
|
228
|
-
}
|
|
246
|
+
warnTarballSuppressedOnce();
|
|
229
247
|
}
|
|
230
248
|
return {
|
|
231
249
|
artifactCount: manifestEntries.length,
|
|
@@ -235,3 +253,10 @@ export class FilesystemArtifactCollector {
|
|
|
235
253
|
};
|
|
236
254
|
}
|
|
237
255
|
}
|
|
256
|
+
let warnedTarballSuppressed = false;
|
|
257
|
+
function warnTarballSuppressedOnce() {
|
|
258
|
+
if (warnedTarballSuppressed)
|
|
259
|
+
return;
|
|
260
|
+
warnedTarballSuppressed = true;
|
|
261
|
+
console.warn("capture.compress is deprecated (W0050); tarball output is no longer produced. The loose directory at <captureDir>/<run>-<ts>-<id>/ contains the same files.");
|
|
262
|
+
}
|
|
@@ -7,24 +7,61 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Paths come from `ARTIFACT_REGISTRY` so writers, signers, and readers agree.
|
|
9
9
|
*
|
|
10
|
+
* ## W0049 API surface
|
|
11
|
+
*
|
|
12
|
+
* - `emit(type, association, payload)` — the canonical single-shot write.
|
|
13
|
+
* Dispatch on `descriptor.layout` is internal; callers pass axis values
|
|
14
|
+
* and the writer resolves the path.
|
|
15
|
+
* - `appendNdjson(type, association, rows)` — streaming-append for `traces`.
|
|
16
|
+
* Each call writes a numbered part object (`.ndjson.part-NNNN`); the
|
|
17
|
+
* parts are composed into the final object lazily at `writeManifest` time
|
|
18
|
+
* via GCS object compose. When a stream accumulates > 32 parts the writer
|
|
19
|
+
* rolls up parts into intermediate composites to stay under the GCS
|
|
20
|
+
* compose cap.
|
|
21
|
+
* - `writeBulk` / `writePerEntry` — @deprecated legacy surface. Removal in W0052.
|
|
22
|
+
*
|
|
10
23
|
* Design principles:
|
|
11
24
|
* - P5: Non-blocking — upload failure returns null, never throws.
|
|
12
25
|
* - Lazy client — Storage created on first write.
|
|
13
26
|
*
|
|
14
27
|
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
28
|
+
* @see docs/decisions/D0033-unified-run-anchored-artifact-capture.md
|
|
15
29
|
*/
|
|
16
|
-
import {
|
|
30
|
+
import { Storage } from "@google-cloud/storage";
|
|
31
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type AssociationValues, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
17
32
|
export interface GcsArtifactWriterOptions {
|
|
18
33
|
/** GCS bucket name (e.g., "ailf-artifacts") */
|
|
19
34
|
bucket: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional pre-constructed Storage client. When omitted the writer
|
|
37
|
+
* constructs one lazily from Application Default Credentials. Test code
|
|
38
|
+
* supplies a fake here to avoid real network calls.
|
|
39
|
+
*/
|
|
40
|
+
storage?: Storage;
|
|
20
41
|
}
|
|
21
42
|
export declare class GcsArtifactWriter implements ArtifactWriter {
|
|
22
43
|
private client;
|
|
23
44
|
private readonly options;
|
|
45
|
+
private readonly ndjsonStreams;
|
|
24
46
|
constructor(options: GcsArtifactWriterOptions);
|
|
47
|
+
emit<T extends ArtifactType>(type: T, association: AssociationValues, payload: unknown): Promise<ArtifactRef | null>;
|
|
48
|
+
appendNdjson<T extends ArtifactType>(type: T, association: AssociationValues, rows: readonly unknown[]): Promise<ArtifactRef | null>;
|
|
49
|
+
writeManifest(runId: RunId, manifest: RunManifest): Promise<ArtifactRef | null>;
|
|
50
|
+
/** @deprecated Use `emit()` instead. Routes through the same GCS I/O. */
|
|
25
51
|
writeBulk(type: ArtifactType, runId: RunId, data: unknown): Promise<ArtifactRef | null>;
|
|
52
|
+
/** @deprecated Use `emit()` per entry instead. */
|
|
26
53
|
writePerEntry(type: ArtifactType, runId: RunId, entries: readonly ArtifactEntry[]): Promise<ArtifactRef | null>;
|
|
27
|
-
|
|
28
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Compose all buffered NDJSON streams into their final objects. Called
|
|
56
|
+
* from `writeManifest` so the manifest is the single sync point for
|
|
57
|
+
* NDJSON finalization.
|
|
58
|
+
*
|
|
59
|
+
* When `partCount > GCS_COMPOSE_MAX`, parts are rolled up in groups of
|
|
60
|
+
* `GCS_COMPOSE_MAX` into intermediate composites, then composed. This
|
|
61
|
+
* stays under the per-call source cap at the cost of one extra round
|
|
62
|
+
* trip per 32 additional parts.
|
|
63
|
+
*/
|
|
64
|
+
private finalizeNdjsonStreams;
|
|
65
|
+
private putBody;
|
|
29
66
|
private getClient;
|
|
30
67
|
}
|