Artifacts: bytes a node produced, addressed by their content

A checkpoint is not a message. DType.ARTIFACT carries a reference — digest,
size, media type, name — so everything on the wire stays JSON and thirty
megabytes never sit in Redis, which answers the vision's open binary-payload
question by narrowing it: inline codecs would only serve payloads too small to
be worth a round trip, and nothing asks for that.

The store is content-addressed rather than per-run, for three reasons that all
pay later: a sweep whose fifty configs share one preprocessed input stores it
once, a reference stays valid however it is passed around because it names
content instead of a location, and the digest is what a stage cache will
compare — so building it in now is what keeps that from being a change to the
message contract.

Node code calls fluksio.save_artifact/load_artifact and cannot tell whether it
is writing the engine's own directory or putting bytes over HTTP, which is
what will let the same flow run on a remote worker unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AD8SfVhzXBG2nAfFcVh3iD
This commit is contained in:
2026-08-18 17:09:27 +02:00
co-authored by Claude Fable 5
parent 3f5bb12ed0
commit b1cb8b41bc
14 changed files with 1481 additions and 93 deletions
+230 -2
View File
@@ -3,7 +3,7 @@
import type { CancelablePromise } from './core/CancelablePromise';
import { OpenAPI } from './core/OpenAPI';
import { request as __request } from './core/request';
import type { AlertsReadAlertsConfigResponse, AlertsSaveAlertsConfigData, AlertsSaveAlertsConfigResponse, AlertsTestChannelData, AlertsTestChannelResponse, DashboardsReadDashboardsResponse, DashboardsReadDashboardData, DashboardsReadDashboardResponse, DashboardsCreateDashboardData, DashboardsCreateDashboardResponse, DashboardsSaveDashboardData, DashboardsSaveDashboardResponse, DashboardsDeleteDashboardData, DashboardsDeleteDashboardResponse, DashboardsPublishDashboardData, DashboardsPublishDashboardResponse, DashboardsDiscardDashboardDraftData, DashboardsDiscardDashboardDraftResponse, DashboardsRenameDashboardData, DashboardsRenameDashboardResponse, FlowsReadFlowsResponse, FlowsReadNodeTypesResponse, FlowsReadGraphResponse, FlowsReadLibraryResponse, FlowsDeleteSharedNodeData, FlowsDeleteSharedNodeResponse, FlowsReadFlowData, FlowsReadFlowResponse, FlowsSaveFlowData, FlowsSaveFlowResponse, FlowsDeleteFlowData, FlowsDeleteFlowResponse, FlowsPublishFlowData, FlowsPublishFlowResponse, FlowsDiscardDraftData, FlowsDiscardDraftResponse, FlowsRenameFlowData, FlowsRenameFlowResponse, FlowsReadNodeSourceData, FlowsReadNodeSourceResponse, FlowsSaveNodeSourceData, FlowsSaveNodeSourceResponse, FlowsShareNodeData, FlowsShareNodeResponse, FlowsUnshareNodeData, FlowsUnshareNodeResponse, FlowsStartFlowData, FlowsStartFlowResponse, FlowsStopFlowData, FlowsStopFlowResponse, FlowsPauseFlowData, FlowsPauseFlowResponse, FlowsResumeFlowData, FlowsResumeFlowResponse, FlowsStepFlowData, FlowsStepFlowResponse, FlowsValidateFlowData, FlowsValidateFlowResponse, FlowsRunFlowData, FlowsRunFlowResponse, FlowsTriggerNodeData, FlowsTriggerNodeResponse, FlowsCancelNodeData, FlowsCancelNodeResponse, FlowsReadFlowStateData, FlowsReadFlowStateResponse, FlowsReadMessageHistoryData, FlowsReadMessageHistoryResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, MessagesReadMessagesResponse, MessagesPublishMessageData, MessagesPublishMessageResponse, MessagesReadMessageHistoryData, MessagesReadMessageHistoryResponse, ModulesReadModulesResponse, ModulesApplyModulesData, ModulesApplyModulesResponse, OauthRegisterClientData, OauthRegisterClientResponse, OauthAuthorizeValidateData, OauthAuthorizeValidateResponse, OauthAuthorizeData, OauthAuthorizeResponse, OauthTokenData, OauthTokenResponse, OauthReadClientsResponse, OauthRevokeClientData, OauthRevokeClientResponse, ObservabilityReadSummaryResponse, ObservabilityReadTimeseriesData, ObservabilityReadTimeseriesResponse, ObservabilityReadFlowRollupsData, ObservabilityReadFlowRollupsResponse, ObservabilityReadRunsData, ObservabilityReadRunsResponse, ObservabilityReadEventsData, ObservabilityReadEventsResponse, ObservabilityReadDeadLettersData, ObservabilityReadDeadLettersResponse, PrivateCreateUserData, PrivateCreateUserResponse, SecretsReadSecretsResponse, SecretsSaveSecretData, SecretsSaveSecretResponse, SecretsDeleteSecretData, SecretsDeleteSecretResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse, UtilsHealthResponse } from './types.gen';
import type { AlertsReadAlertsConfigResponse, AlertsSaveAlertsConfigData, AlertsSaveAlertsConfigResponse, AlertsTestChannelData, AlertsTestChannelResponse, ArtifactsPutArtifactData, ArtifactsPutArtifactResponse, ArtifactsGetArtifactData, ArtifactsGetArtifactResponse, DashboardsReadDashboardsResponse, DashboardsReadDashboardData, DashboardsReadDashboardResponse, DashboardsCreateDashboardData, DashboardsCreateDashboardResponse, DashboardsSaveDashboardData, DashboardsSaveDashboardResponse, DashboardsDeleteDashboardData, DashboardsDeleteDashboardResponse, DashboardsPublishDashboardData, DashboardsPublishDashboardResponse, DashboardsDiscardDashboardDraftData, DashboardsDiscardDashboardDraftResponse, DashboardsRenameDashboardData, DashboardsRenameDashboardResponse, FlowsReadFlowsResponse, FlowsReadNodeTypesResponse, FlowsReadGraphResponse, FlowsReadLibraryResponse, FlowsDeleteSharedNodeData, FlowsDeleteSharedNodeResponse, FlowsReadFlowData, FlowsReadFlowResponse, FlowsSaveFlowData, FlowsSaveFlowResponse, FlowsDeleteFlowData, FlowsDeleteFlowResponse, FlowsPublishFlowData, FlowsPublishFlowResponse, FlowsDiscardDraftData, FlowsDiscardDraftResponse, FlowsRenameFlowData, FlowsRenameFlowResponse, FlowsReadNodeSourceData, FlowsReadNodeSourceResponse, FlowsSaveNodeSourceData, FlowsSaveNodeSourceResponse, FlowsShareNodeData, FlowsShareNodeResponse, FlowsUnshareNodeData, FlowsUnshareNodeResponse, FlowsStartFlowData, FlowsStartFlowResponse, FlowsStopFlowData, FlowsStopFlowResponse, FlowsPauseFlowData, FlowsPauseFlowResponse, FlowsResumeFlowData, FlowsResumeFlowResponse, FlowsStepFlowData, FlowsStepFlowResponse, FlowsValidateFlowData, FlowsValidateFlowResponse, FlowsRunFlowData, FlowsRunFlowResponse, FlowsTriggerNodeData, FlowsTriggerNodeResponse, FlowsCancelNodeData, FlowsCancelNodeResponse, FlowsReadFlowStateData, FlowsReadFlowStateResponse, FlowsReadMessageHistoryData, FlowsReadMessageHistoryResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, MessagesReadMessagesResponse, MessagesPublishMessageData, MessagesPublishMessageResponse, MessagesReadMessageHistoryData, MessagesReadMessageHistoryResponse, ModulesReadModulesResponse, ModulesApplyModulesData, ModulesApplyModulesResponse, OauthRegisterClientData, OauthRegisterClientResponse, OauthAuthorizeValidateData, OauthAuthorizeValidateResponse, OauthAuthorizeData, OauthAuthorizeResponse, OauthTokenData, OauthTokenResponse, OauthReadClientsResponse, OauthRevokeClientData, OauthRevokeClientResponse, ObservabilityReadSummaryResponse, ObservabilityReadTimeseriesData, ObservabilityReadTimeseriesResponse, ObservabilityReadFlowRollupsData, ObservabilityReadFlowRollupsResponse, ObservabilityReadRunsData, ObservabilityReadRunsResponse, ObservabilityReadEventsData, ObservabilityReadEventsResponse, ObservabilityReadDeadLettersData, ObservabilityReadDeadLettersResponse, PrivateCreateUserData, PrivateCreateUserResponse, RunsCreateRunData, RunsCreateRunResponse, RunsCreateSweepData, RunsCreateSweepResponse, RunsReadRunsData, RunsReadRunsResponse, RunsReadRunData, RunsReadRunResponse, RunsCancelRunData, RunsCancelRunResponse, RunsReadMetricsData, RunsReadMetricsResponse, RunsCompareMetricData, RunsCompareMetricResponse, SecretsReadSecretsResponse, SecretsSaveSecretData, SecretsSaveSecretResponse, SecretsDeleteSecretData, SecretsDeleteSecretResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse, UtilsHealthResponse } from './types.gen';
export class AlertsService {
/**
@@ -61,6 +61,52 @@ export class AlertsService {
}
}
export class ArtifactsService {
/**
* Put Artifact
* Store the request body and answer with the reference to it.
* @param data The data for the request.
* @param data.name
* @param data.mediaType
* @returns ArtifactRef Successful Response
* @throws ApiError
*/
public static putArtifact(data: ArtifactsPutArtifactData = {}): CancelablePromise<ArtifactsPutArtifactResponse> {
return __request(OpenAPI, {
method: 'PUT',
url: '/api/v1/artifacts',
query: {
name: data.name,
media_type: data.mediaType
},
errors: {
422: 'Validation Error'
}
});
}
/**
* Get Artifact
* Stream one artifact back.
* @param data The data for the request.
* @param data.digest
* @returns unknown Successful Response
* @throws ApiError
*/
public static getArtifact(data: ArtifactsGetArtifactData): CancelablePromise<ArtifactsGetArtifactResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v1/artifacts/{digest}',
path: {
digest: data.digest
},
errors: {
422: 'Validation Error'
}
});
}
}
export class DashboardsService {
/**
* Read Dashboards
@@ -1210,7 +1256,7 @@ export class ObservabilityService {
* @param data.since
* @param data.until
* @param data.limit
* @returns RunRow Successful Response
* @returns app__api__routes__observability__RunRow Successful Response
* @throws ApiError
*/
public static readRuns(data: ObservabilityReadRunsData = {}): CancelablePromise<ObservabilityReadRunsResponse> {
@@ -1306,6 +1352,188 @@ export class PrivateService {
}
}
export class RunsService {
/**
* Create Run
* Queue one run of a flow.
* @param data The data for the request.
* @param data.name
* @param data.requestBody
* @returns app__api__routes__runs__RunRow Successful Response
* @throws ApiError
*/
public static createRun(data: RunsCreateRunData): CancelablePromise<RunsCreateRunResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v1/runs/flows/{name}',
path: {
name: data.name
},
body: data.requestBody,
mediaType: 'application/json',
errors: {
422: 'Validation Error'
}
});
}
/**
* Create Sweep
* Queue many runs of one flow under a shared group.
*
* An ensemble is this with the same parameters and different seeds; a grid
* search is this with the parameters spread out. Either way the caller
* builds the list — the engine does not own a sweep grammar.
* @param data The data for the request.
* @param data.name
* @param data.requestBody
* @returns app__api__routes__runs__RunRow Successful Response
* @throws ApiError
*/
public static createSweep(data: RunsCreateSweepData): CancelablePromise<RunsCreateSweepResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v1/runs/flows/{name}/sweep',
path: {
name: data.name
},
body: data.requestBody,
mediaType: 'application/json',
errors: {
422: 'Validation Error'
}
});
}
/**
* Read Runs
* Runs, newest first. The queryable table an experiment log needs.
* @param data The data for the request.
* @param data.flow
* @param data.status
* @param data.group
* @param data.digest
* @param data.limit
* @returns app__api__routes__runs__RunRow Successful Response
* @throws ApiError
*/
public static readRuns(data: RunsReadRunsData = {}): CancelablePromise<RunsReadRunsResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v1/runs',
query: {
flow: data.flow,
status: data.status,
group: data.group,
digest: data.digest,
limit: data.limit
},
errors: {
422: 'Validation Error'
}
});
}
/**
* Read Run
* One run in full: what it was asked, what each node did, what it made.
* @param data The data for the request.
* @param data.runId
* @returns RunDetail Successful Response
* @throws ApiError
*/
public static readRun(data: RunsReadRunData): CancelablePromise<RunsReadRunResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v1/runs/{run_id}',
path: {
run_id: data.runId
},
errors: {
422: 'Validation Error'
}
});
}
/**
* Cancel Run
* Stop a run. One already past its last node is left as it finished.
* @param data The data for the request.
* @param data.runId
* @returns app__api__routes__runs__RunRow Successful Response
* @throws ApiError
*/
public static cancelRun(data: RunsCancelRunData): CancelablePromise<RunsCancelRunResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v1/runs/{run_id}/cancel',
path: {
run_id: data.runId
},
errors: {
422: 'Validation Error'
}
});
}
/**
* Read Metrics
* One metric's series, in step order.
*
* ``stride`` thins a long curve down: 3000 steps drawn on a 400-pixel chart
* is 3000 points nobody can see.
* @param data The data for the request.
* @param data.runId
* @param data.name
* @param data.stride
* @returns MetricPoint Successful Response
* @throws ApiError
*/
public static readMetrics(data: RunsReadMetricsData): CancelablePromise<RunsReadMetricsResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v1/runs/{run_id}/metrics',
path: {
run_id: data.runId
},
query: {
name: data.name,
stride: data.stride
},
errors: {
422: 'Validation Error'
}
});
}
/**
* Compare Metric
* One metric across several runs, as the chart widget's series shape.
*
* This is the comparison view: it answers in the same shape a flow answers a
* chart's query with, so putting three training curves beside each other is
* a widget binding rather than a screen of its own.
* @param data The data for the request.
* @param data.ids
* @param data.metric
* @returns SeriesAnswer Successful Response
* @throws ApiError
*/
public static compareMetric(data: RunsCompareMetricData): CancelablePromise<RunsCompareMetricResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v1/runs/series/compare',
query: {
ids: data.ids,
metric: data.metric
},
errors: {
422: 'Validation Error'
}
});
}
}
export class SecretsService {
/**
* Read Secrets