@sanity/ailf 2.7.1 → 2.8.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-registry.d.ts +72 -0
- package/dist/_vendor/ailf-core/artifact-registry.js +150 -0
- 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-collector.d.ts +3 -3
- package/dist/_vendor/ailf-core/ports/artifact-writer.d.ts +56 -0
- package/dist/_vendor/ailf-core/ports/artifact-writer.js +28 -0
- package/dist/_vendor/ailf-core/ports/context.d.ts +13 -3
- package/dist/_vendor/ailf-core/ports/index.d.ts +3 -3
- package/dist/_vendor/ailf-core/ports/index.js +1 -1
- package/dist/_vendor/ailf-core/types/branded-ids.d.ts +9 -0
- package/dist/_vendor/ailf-core/types/branded-ids.js +21 -0
- package/dist/_vendor/ailf-core/types/index.d.ts +110 -68
- package/dist/_vendor/ailf-core/types/index.js +1 -1
- package/dist/_vendor/ailf-shared/index.d.ts +2 -0
- package/dist/_vendor/ailf-shared/index.js +2 -0
- package/dist/_vendor/ailf-shared/run-context.d.ts +55 -0
- package/dist/_vendor/ailf-shared/run-context.js +17 -0
- package/dist/_vendor/ailf-shared/run-trigger.d.ts +30 -0
- package/dist/_vendor/ailf-shared/run-trigger.js +13 -0
- package/dist/artifact-capture/api-gateway-artifact-writer.d.ts +39 -0
- package/dist/artifact-capture/api-gateway-artifact-writer.js +148 -0
- package/dist/artifact-capture/gcs-artifact-writer.d.ts +30 -0
- package/dist/artifact-capture/gcs-artifact-writer.js +119 -0
- package/dist/commands/publish.js +3 -2
- package/dist/composition-root.d.ts +3 -3
- package/dist/composition-root.js +20 -15
- package/dist/orchestration/build-step-sequence.js +6 -1
- package/dist/orchestration/steps/calculate-scores-step.js +42 -2
- package/dist/orchestration/steps/finalize-run-step.d.ts +29 -0
- package/dist/orchestration/steps/finalize-run-step.js +103 -0
- package/dist/orchestration/steps/publish-report-step.js +19 -39
- package/dist/pipeline/calculate-scores.js +13 -2
- package/dist/pipeline/provenance.d.ts +24 -44
- package/dist/pipeline/provenance.js +17 -165
- package/dist/pipeline/report-title.d.ts +2 -2
- package/dist/pipeline/run-context.d.ts +57 -0
- package/dist/pipeline/run-context.js +156 -0
- package/dist/pipeline/upload-test-outputs.d.ts +26 -0
- package/dist/pipeline/upload-test-outputs.js +34 -0
- package/dist/report-store.js +4 -2
- package/package.json +3 -3
- package/dist/_vendor/ailf-core/ports/artifact-uploader.d.ts +0 -35
- package/dist/_vendor/ailf-core/ports/artifact-uploader.js +0 -18
- package/dist/artifact-capture/api-gateway-artifact-uploader.d.ts +0 -41
- package/dist/artifact-capture/api-gateway-artifact-uploader.js +0 -123
- package/dist/artifact-capture/gcs-report-artifact-uploader.d.ts +0 -31
- package/dist/artifact-capture/gcs-report-artifact-uploader.js +0 -66
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* Ports & Adapters migration (Phase 0c). The original file is now a
|
|
10
10
|
* re-export barrel that preserves backward compatibility.
|
|
11
11
|
*/
|
|
12
|
-
import type { DocumentRef as _DocumentRef, EvalMode } from "../../ailf-shared/index.d.ts";
|
|
12
|
+
import type { DocumentRef as _DocumentRef, EvalMode, RunContext } from "../../ailf-shared/index.d.ts";
|
|
13
|
+
import type { RunId } from "./branded-ids.js";
|
|
13
14
|
export type { ActualScoreEntry, ComponentResult, TestResult, UrlMetadata, } from "./scoring-input.js";
|
|
14
|
-
export type { DocumentRef } from "../../ailf-shared/index.d.ts";
|
|
15
|
+
export type { DocumentRef, RunContext, RunTrigger } from "../../ailf-shared/index.d.ts";
|
|
15
16
|
export type { StoredBaseline, StoredReport, StoredRun, StoredTaskResult, StoredTrace, SchemaVersioned, } from "./storage-schema.js";
|
|
16
17
|
export { CURRENT_SCHEMA_VERSION, isSchemaVersioned, migrateDocument, } from "./storage-schema.js";
|
|
17
18
|
export type { AssertionRegistration, FixtureResolverRegistration, ModeBase, ModeRegistration, PluginManifest, PluginRegistry, PresetDefinition, ReportSinkRegistration, RubricTemplateRegistration, } from "./plugin-registry.js";
|
|
@@ -22,7 +23,7 @@ export type { DependencyEdge, ResolvedFixture, TaskGraph, TaskNode, } from "./ta
|
|
|
22
23
|
export type { VariableDeclaration, VariableEnvelope, VariableProvenance, VariableSource, } from "./variable-envelope.js";
|
|
23
24
|
export type { EvalTrace, ToolCallCategory, ToolCallRecord, TraceEvent, TraceSpan, TraceTokenUsage, } from "./trace.js";
|
|
24
25
|
export type { ArtifactId, Brand, Err, FixtureId, IdValidationError, NewReportId, Ok, ProviderId, PromptId, Result, ResultId, RubricId, RunFingerprint, RunId, SuiteId, TaskId, TaskSlug, TraceId, } from "./branded-ids.js";
|
|
25
|
-
export { err, fixtureId, ok, providerId, resultId, runId, suiteId, taskId, traceId, } from "./branded-ids.js";
|
|
26
|
+
export { err, fixtureId, generateRunId, ok, providerId, resultId, runId, suiteId, taskId, traceId, } from "./branded-ids.js";
|
|
26
27
|
export type { AgentHarnessTaskDefinition, CustomTaskDefinition, GeneralizedAssertionDefinition, GeneralizedDocRef, GeneralizedTaskDefinition, GeneralizedTemplatedAssertion, GeneralizedValueAssertion, IdDocRef, KnowledgeProbeTaskDefinition, LiteracyTaskDefinition, MCPServerTaskDefinition, PathDocRef, PerspectiveDocRef, RubricRef, SlugDocRef, TaskCommonFields, TaskDifficulty, TaskOptions, TaskProviderConfig, TaskStatus, } from "./generalized-task.js";
|
|
27
28
|
type DocumentRef = _DocumentRef;
|
|
28
29
|
/** Aggregated retrieval metrics for a feature area */
|
|
@@ -536,6 +537,19 @@ export interface PromptfooUrlEntry {
|
|
|
536
537
|
* only matter during a single pipeline execution.
|
|
537
538
|
*/
|
|
538
539
|
export interface PipelineState {
|
|
540
|
+
/**
|
|
541
|
+
* Artifact refs produced by upstream steps during the run.
|
|
542
|
+
* Populated incrementally (CalculateScoresStep writes testOutputs; future
|
|
543
|
+
* steps will write renderedPrompts, traces, etc.). Read by FinalizeRunStep
|
|
544
|
+
* to build the `RunManifest.artifacts` catalog.
|
|
545
|
+
*/
|
|
546
|
+
artifactRefs?: Partial<ArtifactManifest>;
|
|
547
|
+
/**
|
|
548
|
+
* The run manifest, finalized and written to `runs/{runId}/manifest.json`.
|
|
549
|
+
* Populated by FinalizeRunStep. Consumed by PublishReportStep to snapshot
|
|
550
|
+
* the `artifacts` slice into `Report.artifactManifest` (D0032).
|
|
551
|
+
*/
|
|
552
|
+
runManifest?: RunManifest;
|
|
539
553
|
/** Report ID generated by PublishReportStep, consumed by CallbackStep + orchestrator job update */
|
|
540
554
|
reportId?: string;
|
|
541
555
|
/** Eval fingerprint computed by RunEvalStep, consumed by PublishReportStep */
|
|
@@ -1162,23 +1176,52 @@ export interface PublishResult {
|
|
|
1162
1176
|
result: SinkResult;
|
|
1163
1177
|
}[];
|
|
1164
1178
|
}
|
|
1165
|
-
/**
|
|
1179
|
+
/**
|
|
1180
|
+
* Reference to an artifact in external object storage (GCS). See D0032.
|
|
1181
|
+
*
|
|
1182
|
+
* `layout` determines the on-disk shape:
|
|
1183
|
+
* - `"bulk"` — a single object at `path`. `entries` is absent.
|
|
1184
|
+
* - `"per-entry"` — `path` is a directory prefix. Each entry is a
|
|
1185
|
+
* separate object at `{path}/{sanitizedKey}.json`. `entries` inlines
|
|
1186
|
+
* the catalog so consumers can render drill-down states without a
|
|
1187
|
+
* second list call.
|
|
1188
|
+
*/
|
|
1166
1189
|
export interface ArtifactRef {
|
|
1167
1190
|
store: "gcs";
|
|
1168
1191
|
bucket: string;
|
|
1169
1192
|
path: string;
|
|
1170
1193
|
bytes?: number;
|
|
1171
1194
|
entryCount?: number;
|
|
1195
|
+
layout: "bulk" | "per-entry";
|
|
1196
|
+
entries?: {
|
|
1197
|
+
key: string;
|
|
1198
|
+
bytes: number;
|
|
1199
|
+
}[];
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Catalog of artifact refs produced by a single pipeline run.
|
|
1203
|
+
*
|
|
1204
|
+
* Lives on `RunManifest.artifacts` (source of truth in GCS) and is
|
|
1205
|
+
* snapshotted onto `Report.artifactManifest` at publish time.
|
|
1206
|
+
*/
|
|
1207
|
+
export interface ArtifactManifest {
|
|
1208
|
+
testOutputs?: ArtifactRef;
|
|
1209
|
+
renderedPrompts?: ArtifactRef;
|
|
1210
|
+
rawResults?: ArtifactRef;
|
|
1211
|
+
graderPrompts?: ArtifactRef;
|
|
1212
|
+
taskDefinitions?: ArtifactRef;
|
|
1213
|
+
evalResults?: ArtifactRef;
|
|
1214
|
+
traces?: ArtifactRef;
|
|
1172
1215
|
}
|
|
1173
1216
|
/** A published evaluation report — the atomic unit of the report store */
|
|
1174
1217
|
export interface Report {
|
|
1175
|
-
/**
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1218
|
+
/**
|
|
1219
|
+
* Snapshot of the run manifest's `artifacts` slice at publish time (D0032).
|
|
1220
|
+
* The source of truth lives in `gs://…/runs/{runId}/manifest.json`; this
|
|
1221
|
+
* field denormalizes enough information for Studio to render drill-down
|
|
1222
|
+
* states without an extra manifest fetch.
|
|
1223
|
+
*/
|
|
1224
|
+
artifactManifest?: ArtifactManifest;
|
|
1182
1225
|
/** Optional auto-comparison against the most recent comparable report */
|
|
1183
1226
|
comparison?: ComparisonReport;
|
|
1184
1227
|
/** When the evaluation completed */
|
|
@@ -1239,76 +1282,75 @@ export interface ReportLineage {
|
|
|
1239
1282
|
*/
|
|
1240
1283
|
rerunOf?: ReportId;
|
|
1241
1284
|
}
|
|
1242
|
-
/**
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1285
|
+
/**
|
|
1286
|
+
* Full provenance metadata for an evaluation report.
|
|
1287
|
+
*
|
|
1288
|
+
* Inherits the 9 run-description fields (mode, areas, taskIds, models,
|
|
1289
|
+
* graderModel, source, evalFingerprint, trigger, git) from `RunContext`.
|
|
1290
|
+
* Adding a field to `RunContext` makes it available here automatically —
|
|
1291
|
+
* the structural extension is the drift-prevention mechanism described in
|
|
1292
|
+
* D0032 § "Drift Prevention".
|
|
1293
|
+
*/
|
|
1294
|
+
export interface ReportProvenance extends RunContext {
|
|
1246
1295
|
/** Release auto-scope metadata (when perspective evaluation was scoped to affected tasks) */
|
|
1247
1296
|
autoScope?: ReportAutoScope;
|
|
1248
1297
|
/** Content hash of the documentation context at eval time */
|
|
1249
1298
|
contextHash?: string;
|
|
1250
|
-
/**
|
|
1251
|
-
* Evaluation fingerprint — SHA-256 of all inputs that affect eval output.
|
|
1252
|
-
* Used for cross-environment cache lookup (CI → Content Lake).
|
|
1253
|
-
* @see docs/design-docs/content-lake-eval-caching.md
|
|
1254
|
-
*/
|
|
1255
|
-
evalFingerprint?: string;
|
|
1256
|
-
/** Git metadata (when run from CI) */
|
|
1257
|
-
git?: {
|
|
1258
|
-
branch: string;
|
|
1259
|
-
prNumber?: number;
|
|
1260
|
-
repo: string;
|
|
1261
|
-
sha: string;
|
|
1262
|
-
};
|
|
1263
|
-
/** Grader model used for scoring */
|
|
1264
|
-
graderModel: string;
|
|
1265
1299
|
/** Typed relationships with other reports (re-run, comparison) */
|
|
1266
1300
|
lineage?: ReportLineage;
|
|
1267
|
-
/** Evaluation mode */
|
|
1268
|
-
mode: EvalMode;
|
|
1269
|
-
/** Models under evaluation */
|
|
1270
|
-
models: {
|
|
1271
|
-
id: string;
|
|
1272
|
-
label: string;
|
|
1273
|
-
}[];
|
|
1274
1301
|
/** @deprecated Use `promptfooUrls` — kept for backward compatibility */
|
|
1275
1302
|
promptfooUrl?: string;
|
|
1276
1303
|
/** Per-mode Promptfoo share URLs (one per sub-eval that produced a shareable link) */
|
|
1277
1304
|
promptfooUrls?: PromptfooUrlEntry[];
|
|
1278
|
-
/**
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
projectId?: string;
|
|
1285
|
-
};
|
|
1305
|
+
/**
|
|
1306
|
+
* Identity of the pipeline run that produced this report. Links the
|
|
1307
|
+
* Content Lake document back to the GCS run manifest and its artifacts.
|
|
1308
|
+
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
1309
|
+
*/
|
|
1310
|
+
runId: RunId;
|
|
1286
1311
|
/** Sanity document IDs that were targeted (if using --sanity-document) */
|
|
1287
1312
|
targetDocuments?: string[];
|
|
1288
|
-
/** Which specific task IDs were evaluated (if scoped) */
|
|
1289
|
-
taskIds?: string[];
|
|
1290
|
-
/** What initiated this evaluation */
|
|
1291
|
-
trigger: ReportTrigger;
|
|
1292
1313
|
}
|
|
1293
|
-
/**
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1314
|
+
/**
|
|
1315
|
+
* A run's manifest in GCS (`runs/{runId}/manifest.json`). Source of truth
|
|
1316
|
+
* for artifact locations, run identity, and outcome. Reports snapshot the
|
|
1317
|
+
* `artifacts` slice into `Report.artifactManifest` at publish time.
|
|
1318
|
+
*
|
|
1319
|
+
* Written once by `FinalizeRunStep`; `reportIds` may be appended by
|
|
1320
|
+
* `PublishReportStep` via strongly-consistent GCS overwrite.
|
|
1321
|
+
*/
|
|
1322
|
+
export interface RunManifest {
|
|
1323
|
+
/** Schema version — bumped when the manifest shape changes */
|
|
1324
|
+
version: 1;
|
|
1325
|
+
/** Identity for this pipeline run */
|
|
1326
|
+
runId: RunId;
|
|
1327
|
+
/** When the manifest was written (pipeline finalization time) */
|
|
1328
|
+
createdAt: ISOTimestamp;
|
|
1329
|
+
/** Total pipeline duration */
|
|
1330
|
+
durationMs: number;
|
|
1331
|
+
/** Outcome of the run */
|
|
1332
|
+
status: "completed" | "failed" | "partial";
|
|
1333
|
+
/** Failure classification when status is not "completed" */
|
|
1334
|
+
failureReason?: PipelineFailureReason;
|
|
1335
|
+
/** What ran — shared shape with ReportProvenance */
|
|
1336
|
+
context: RunContext;
|
|
1337
|
+
/** Run-level aggregates (self-describing without a report) */
|
|
1338
|
+
outcomes?: {
|
|
1339
|
+
testSummary?: TestSummary;
|
|
1340
|
+
usage?: PipelineUsage;
|
|
1341
|
+
cache?: {
|
|
1342
|
+
hits: number;
|
|
1343
|
+
misses: number;
|
|
1344
|
+
skipped: number;
|
|
1345
|
+
};
|
|
1346
|
+
};
|
|
1347
|
+
/** Reports published from this run (0..N). Authoritative link is Report.provenance.runId. */
|
|
1348
|
+
reportIds?: ReportId[];
|
|
1349
|
+
/** Promptfoo share URLs collected during the run */
|
|
1350
|
+
promptfooUrls?: PromptfooUrlEntry[];
|
|
1351
|
+
/** Artifact catalog — per-type refs with inline per-entry indexes */
|
|
1352
|
+
artifacts: ArtifactManifest;
|
|
1353
|
+
}
|
|
1312
1354
|
/** Health check result for a sink */
|
|
1313
1355
|
export type SinkHealthStatus = {
|
|
1314
1356
|
healthy: false;
|
|
@@ -16,7 +16,7 @@ export { InMemoryPluginRegistry } from "./plugin-registry.js";
|
|
|
16
16
|
// version is used internally by LiteracyModeConfig. If consumers need
|
|
17
17
|
// the mode-specific version, they import from "./eval-mode-config.js".
|
|
18
18
|
export { evalModeType } from "./eval-mode-config.js";
|
|
19
|
-
export { err, fixtureId, ok, providerId, resultId, runId, suiteId, taskId, traceId, } from "./branded-ids.js";
|
|
19
|
+
export { err, fixtureId, generateRunId, ok, providerId, resultId, runId, suiteId, taskId, traceId, } from "./branded-ids.js";
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
// Comparison (Approach 2: structured comparison output)
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunContext — the set of fields that describe an AILF pipeline run.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for run-description data. Both
|
|
5
|
+
* `RunManifest.context` (in GCS, written by FinalizeRunStep) and
|
|
6
|
+
* `ReportProvenance` (in Content Lake, built by PublishReportStep)
|
|
7
|
+
* carry this shape. `ReportProvenance extends RunContext` to
|
|
8
|
+
* structurally enforce parity — adding a field here becomes a
|
|
9
|
+
* compile-time failure until every consumer threads it through.
|
|
10
|
+
*
|
|
11
|
+
* Fields are alphabetized to match the surrounding codebase convention
|
|
12
|
+
* (see `ReportProvenance` in `@sanity/ailf-core`).
|
|
13
|
+
*
|
|
14
|
+
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
15
|
+
* @see docs/design-docs/run-artifact-store.md (§ Drift Prevention)
|
|
16
|
+
*/
|
|
17
|
+
import type { EvalMode } from "./eval-modes.js";
|
|
18
|
+
import type { RunTrigger } from "./run-trigger.js";
|
|
19
|
+
export interface RunContext {
|
|
20
|
+
/** Which feature areas were evaluated */
|
|
21
|
+
areas: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Evaluation fingerprint — SHA-256 of all inputs that affect eval output.
|
|
24
|
+
* Used for cross-environment cache lookup (CI → Content Lake).
|
|
25
|
+
*/
|
|
26
|
+
evalFingerprint?: string;
|
|
27
|
+
/** Git metadata (when run from CI) */
|
|
28
|
+
git?: {
|
|
29
|
+
branch: string;
|
|
30
|
+
prNumber?: number;
|
|
31
|
+
repo: string;
|
|
32
|
+
sha: string;
|
|
33
|
+
};
|
|
34
|
+
/** Grader model used for scoring */
|
|
35
|
+
graderModel: string;
|
|
36
|
+
/** Evaluation mode */
|
|
37
|
+
mode: EvalMode;
|
|
38
|
+
/** Models under evaluation */
|
|
39
|
+
models: {
|
|
40
|
+
id: string;
|
|
41
|
+
label: string;
|
|
42
|
+
}[];
|
|
43
|
+
/** Documentation source configuration */
|
|
44
|
+
source: {
|
|
45
|
+
baseUrl: string;
|
|
46
|
+
dataset?: string;
|
|
47
|
+
name: string;
|
|
48
|
+
perspective?: string;
|
|
49
|
+
projectId?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Specific task IDs evaluated when scoped to a subset */
|
|
52
|
+
taskIds?: string[];
|
|
53
|
+
/** What initiated this run */
|
|
54
|
+
trigger: RunTrigger;
|
|
55
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunContext — the set of fields that describe an AILF pipeline run.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for run-description data. Both
|
|
5
|
+
* `RunManifest.context` (in GCS, written by FinalizeRunStep) and
|
|
6
|
+
* `ReportProvenance` (in Content Lake, built by PublishReportStep)
|
|
7
|
+
* carry this shape. `ReportProvenance extends RunContext` to
|
|
8
|
+
* structurally enforce parity — adding a field here becomes a
|
|
9
|
+
* compile-time failure until every consumer threads it through.
|
|
10
|
+
*
|
|
11
|
+
* Fields are alphabetized to match the surrounding codebase convention
|
|
12
|
+
* (see `ReportProvenance` in `@sanity/ailf-core`).
|
|
13
|
+
*
|
|
14
|
+
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
15
|
+
* @see docs/design-docs/run-artifact-store.md (§ Drift Prevention)
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunTrigger — what initiated a pipeline run.
|
|
3
|
+
*
|
|
4
|
+
* Lives in shared so it can be referenced from RunContext (the single
|
|
5
|
+
* source of truth for run-description fields) and consumed by both
|
|
6
|
+
* RunManifest (GCS) and ReportProvenance (Content Lake) without creating
|
|
7
|
+
* a core → core cycle.
|
|
8
|
+
*
|
|
9
|
+
* The `ci.runId` field is the external workflow run identifier (e.g.
|
|
10
|
+
* GitHub Actions run ID). It is unrelated to the pipeline-level `RunId`
|
|
11
|
+
* brand in `@sanity/ailf-core`, which identifies an AILF pipeline run.
|
|
12
|
+
*/
|
|
13
|
+
export type RunTrigger = {
|
|
14
|
+
type: "ci";
|
|
15
|
+
runId: string;
|
|
16
|
+
workflow: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: "cross-repo";
|
|
19
|
+
callerRef?: string;
|
|
20
|
+
callerRepo: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "manual";
|
|
23
|
+
} | {
|
|
24
|
+
type: "scheduled";
|
|
25
|
+
schedule: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: "webhook";
|
|
28
|
+
documentId?: string;
|
|
29
|
+
source: string;
|
|
30
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunTrigger — what initiated a pipeline run.
|
|
3
|
+
*
|
|
4
|
+
* Lives in shared so it can be referenced from RunContext (the single
|
|
5
|
+
* source of truth for run-description fields) and consumed by both
|
|
6
|
+
* RunManifest (GCS) and ReportProvenance (Content Lake) without creating
|
|
7
|
+
* a core → core cycle.
|
|
8
|
+
*
|
|
9
|
+
* The `ci.runId` field is the external workflow run identifier (e.g.
|
|
10
|
+
* GitHub Actions run ID). It is unrelated to the pipeline-level `RunId`
|
|
11
|
+
* brand in `@sanity/ailf-core`, which identifies an AILF pipeline run.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApiGatewayArtifactWriter — uploads AILF run artifacts via the API Gateway.
|
|
3
|
+
*
|
|
4
|
+
* Used when the CLI runs locally without GCS credentials. The Gateway signs a
|
|
5
|
+
* PUT URL (scoped to a single GCS object) and the writer PUTs JSON directly
|
|
6
|
+
* to GCS so Vercel stays out of the data path.
|
|
7
|
+
*
|
|
8
|
+
* Endpoints:
|
|
9
|
+
* - Bulk: GET {apiBaseUrl}/v1/runs/{runId}/artifacts/{type}/upload-url
|
|
10
|
+
* - Per-entry: GET {apiBaseUrl}/v1/runs/{runId}/artifacts/{type}/{entryKey}/upload-url
|
|
11
|
+
* - Manifest: GET {apiBaseUrl}/v1/runs/{runId}/artifacts/manifest/upload-url
|
|
12
|
+
*
|
|
13
|
+
* The Gateway routes are wired in Phase 10 (W0047).
|
|
14
|
+
*
|
|
15
|
+
* Design principles:
|
|
16
|
+
* - P5: Non-blocking — any failure returns null and warns, never throws.
|
|
17
|
+
* - Stateless — no client state between calls.
|
|
18
|
+
*
|
|
19
|
+
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
20
|
+
*/
|
|
21
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
22
|
+
export interface ApiGatewayArtifactWriterOptions {
|
|
23
|
+
/** Base URL of the API gateway (e.g., "https://ailf-api.sanity.build"). */
|
|
24
|
+
apiBaseUrl: string;
|
|
25
|
+
/** AILF API key with the `artifact:write` scope. */
|
|
26
|
+
apiKey: string;
|
|
27
|
+
/** GCS bucket name — included in the returned ArtifactRef. */
|
|
28
|
+
bucket: string;
|
|
29
|
+
}
|
|
30
|
+
export declare class ApiGatewayArtifactWriter implements ArtifactWriter {
|
|
31
|
+
private readonly options;
|
|
32
|
+
constructor(options: ApiGatewayArtifactWriterOptions);
|
|
33
|
+
writeBulk(type: ArtifactType, runId: RunId, data: unknown): Promise<ArtifactRef | null>;
|
|
34
|
+
writePerEntry(type: ArtifactType, runId: RunId, entries: readonly ArtifactEntry[]): Promise<ArtifactRef | null>;
|
|
35
|
+
writeManifest(runId: RunId, manifest: RunManifest): Promise<ArtifactRef | null>;
|
|
36
|
+
private putJson;
|
|
37
|
+
private putJsonRaw;
|
|
38
|
+
private fetchSignedUrl;
|
|
39
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApiGatewayArtifactWriter — uploads AILF run artifacts via the API Gateway.
|
|
3
|
+
*
|
|
4
|
+
* Used when the CLI runs locally without GCS credentials. The Gateway signs a
|
|
5
|
+
* PUT URL (scoped to a single GCS object) and the writer PUTs JSON directly
|
|
6
|
+
* to GCS so Vercel stays out of the data path.
|
|
7
|
+
*
|
|
8
|
+
* Endpoints:
|
|
9
|
+
* - Bulk: GET {apiBaseUrl}/v1/runs/{runId}/artifacts/{type}/upload-url
|
|
10
|
+
* - Per-entry: GET {apiBaseUrl}/v1/runs/{runId}/artifacts/{type}/{entryKey}/upload-url
|
|
11
|
+
* - Manifest: GET {apiBaseUrl}/v1/runs/{runId}/artifacts/manifest/upload-url
|
|
12
|
+
*
|
|
13
|
+
* The Gateway routes are wired in Phase 10 (W0047).
|
|
14
|
+
*
|
|
15
|
+
* Design principles:
|
|
16
|
+
* - P5: Non-blocking — any failure returns null and warns, never throws.
|
|
17
|
+
* - Stateless — no client state between calls.
|
|
18
|
+
*
|
|
19
|
+
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
20
|
+
*/
|
|
21
|
+
import { ARTIFACT_REGISTRY, } from "../_vendor/ailf-core/index.js";
|
|
22
|
+
export class ApiGatewayArtifactWriter {
|
|
23
|
+
options;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.options = options;
|
|
26
|
+
}
|
|
27
|
+
async writeBulk(type, runId, data) {
|
|
28
|
+
const uploadUrlPath = `/v1/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(type)}/upload-url`;
|
|
29
|
+
return this.putJson(uploadUrlPath, data, {
|
|
30
|
+
layout: "bulk",
|
|
31
|
+
entryCount: entryCountOf(data),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async writePerEntry(type, runId, entries) {
|
|
35
|
+
const descriptor = ARTIFACT_REGISTRY[type];
|
|
36
|
+
if (!descriptor.parseEntryKey) {
|
|
37
|
+
console.warn(` ⚠️ writePerEntry called for "${type}" but the registry has no parseEntryKey`);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const uploaded = [];
|
|
41
|
+
let totalBytes = 0;
|
|
42
|
+
let bucket = this.options.bucket;
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const parsed = descriptor.parseEntryKey(entry.key);
|
|
45
|
+
if (!parsed.ok) {
|
|
46
|
+
console.warn(` ⚠️ Skipping entry with invalid key "${entry.key}": ${parsed.reason}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const uploadUrlPath = `/v1/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(type)}/${encodeURIComponent(entry.key)}/upload-url`;
|
|
50
|
+
const result = await this.putJsonRaw(uploadUrlPath, entry.data);
|
|
51
|
+
if (!result)
|
|
52
|
+
continue;
|
|
53
|
+
bucket = result.bucket;
|
|
54
|
+
uploaded.push({ key: entry.key, bytes: result.bytes });
|
|
55
|
+
totalBytes += result.bytes;
|
|
56
|
+
}
|
|
57
|
+
if (uploaded.length === 0)
|
|
58
|
+
return null;
|
|
59
|
+
return {
|
|
60
|
+
store: "gcs",
|
|
61
|
+
bucket,
|
|
62
|
+
path: `runs/${runId}/${descriptor.slug}`,
|
|
63
|
+
bytes: totalBytes,
|
|
64
|
+
entryCount: uploaded.length,
|
|
65
|
+
layout: "per-entry",
|
|
66
|
+
entries: uploaded,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async writeManifest(runId, manifest) {
|
|
70
|
+
const uploadUrlPath = `/v1/runs/${encodeURIComponent(runId)}/artifacts/manifest/upload-url`;
|
|
71
|
+
return this.putJson(uploadUrlPath, manifest, { layout: "bulk" });
|
|
72
|
+
}
|
|
73
|
+
async putJson(uploadUrlPath, data, meta) {
|
|
74
|
+
const result = await this.putJsonRaw(uploadUrlPath, data);
|
|
75
|
+
if (!result)
|
|
76
|
+
return null;
|
|
77
|
+
return {
|
|
78
|
+
store: "gcs",
|
|
79
|
+
bucket: result.bucket,
|
|
80
|
+
path: result.path,
|
|
81
|
+
bytes: result.bytes,
|
|
82
|
+
entryCount: meta.entryCount,
|
|
83
|
+
layout: meta.layout,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async putJsonRaw(uploadUrlPath, data) {
|
|
87
|
+
const json = JSON.stringify(data);
|
|
88
|
+
const bytes = Buffer.byteLength(json, "utf-8");
|
|
89
|
+
try {
|
|
90
|
+
const signed = await this.fetchSignedUrl(uploadUrlPath);
|
|
91
|
+
if (!signed)
|
|
92
|
+
return null;
|
|
93
|
+
const putRes = await fetch(signed.url, {
|
|
94
|
+
body: json,
|
|
95
|
+
headers: signed.requiredHeaders,
|
|
96
|
+
method: "PUT",
|
|
97
|
+
});
|
|
98
|
+
if (!putRes.ok) {
|
|
99
|
+
console.warn(` ⚠️ Artifact upload failed (non-blocking): ${signed.path} — GCS PUT ${putRes.status} ${putRes.statusText}`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return { bucket: signed.bucket, path: signed.path, bytes };
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
106
|
+
console.warn(` ⚠️ Artifact upload failed (non-blocking): ${uploadUrlPath} — ${message}`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async fetchSignedUrl(uploadUrlPath) {
|
|
111
|
+
const url = `${this.options.apiBaseUrl.replace(/\/$/, "")}${uploadUrlPath}`;
|
|
112
|
+
const res = await fetch(url, {
|
|
113
|
+
headers: { Authorization: `Bearer ${this.options.apiKey}` },
|
|
114
|
+
method: "GET",
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
console.warn(` ⚠️ Signed-URL request failed: ${res.status} ${res.statusText}`);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
const body = (await res.json());
|
|
121
|
+
if (body.object !== "signed_upload_url" ||
|
|
122
|
+
typeof body.url !== "string" ||
|
|
123
|
+
typeof body.path !== "string" ||
|
|
124
|
+
typeof body.bucket !== "string" ||
|
|
125
|
+
!body.requiredHeaders) {
|
|
126
|
+
console.warn(` ⚠️ Signed-URL response was malformed`);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
bucket: body.bucket,
|
|
131
|
+
method: "PUT",
|
|
132
|
+
object: "signed_upload_url",
|
|
133
|
+
path: body.path,
|
|
134
|
+
requiredHeaders: body.requiredHeaders,
|
|
135
|
+
url: body.url,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function entryCountOf(data) {
|
|
140
|
+
if (typeof data === "object" &&
|
|
141
|
+
data !== null &&
|
|
142
|
+
"entries" in data &&
|
|
143
|
+
typeof data.entries === "object") {
|
|
144
|
+
return Object.keys(data.entries)
|
|
145
|
+
.length;
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GcsArtifactWriter — writes AILF run artifacts + manifest directly to GCS.
|
|
3
|
+
*
|
|
4
|
+
* Uses Application Default Credentials (ADC). Used when the CLI runs in CI or
|
|
5
|
+
* anywhere ADC is configured — the client talks to GCS without the API Gateway
|
|
6
|
+
* acting as a middleman.
|
|
7
|
+
*
|
|
8
|
+
* Paths come from `ARTIFACT_REGISTRY` so writers, signers, and readers agree.
|
|
9
|
+
*
|
|
10
|
+
* Design principles:
|
|
11
|
+
* - P5: Non-blocking — upload failure returns null, never throws.
|
|
12
|
+
* - Lazy client — Storage created on first write.
|
|
13
|
+
*
|
|
14
|
+
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
15
|
+
*/
|
|
16
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
17
|
+
export interface GcsArtifactWriterOptions {
|
|
18
|
+
/** GCS bucket name (e.g., "ailf-artifacts") */
|
|
19
|
+
bucket: string;
|
|
20
|
+
}
|
|
21
|
+
export declare class GcsArtifactWriter implements ArtifactWriter {
|
|
22
|
+
private client;
|
|
23
|
+
private readonly options;
|
|
24
|
+
constructor(options: GcsArtifactWriterOptions);
|
|
25
|
+
writeBulk(type: ArtifactType, runId: RunId, data: unknown): Promise<ArtifactRef | null>;
|
|
26
|
+
writePerEntry(type: ArtifactType, runId: RunId, entries: readonly ArtifactEntry[]): Promise<ArtifactRef | null>;
|
|
27
|
+
writeManifest(runId: RunId, manifest: RunManifest): Promise<ArtifactRef | null>;
|
|
28
|
+
private putJson;
|
|
29
|
+
private getClient;
|
|
30
|
+
}
|