refactor: add run store HTTP endpoints

Define the new run-store contract in the OpenAPI spec, regenerate the
Rust and TypeScript clients, and implement the matching store and
server support for run state, event access, blobs, and stage artifacts.
This commit is contained in:
Bryan Helmkamp 2026-04-04 15:37:33 -04:00
parent ddebb888b6
commit 39980b5404
No known key found for this signature in database
25 changed files with 2554 additions and 127 deletions

View file

@ -335,14 +335,93 @@ paths:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/events:
/api/v1/runs/{id}/state:
get:
operationId: streamRunEvents
tags: [Runs]
summary: Stream Run Events
description: Opens a server-sent event (SSE) stream for real-time run updates. Returns 410 if the stream has been closed.
operationId: getRunState
tags: [Run Internals]
summary: Get Run State
description: Returns the internal event-sourced run projection. This is not a stable public contract.
parameters:
- $ref: "#/components/parameters/RunId"
responses:
"200":
description: Current run projection
content:
application/json:
schema:
$ref: "#/components/schemas/RunProjection"
"404":
description: Run not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/events:
get:
operationId: listRunEvents
tags: [Run Internals]
summary: List Run Events
description: Returns a paginated JSON list of stored run events.
parameters:
- $ref: "#/components/parameters/RunId"
- $ref: "#/components/parameters/SinceSeq"
- $ref: "#/components/parameters/EventLimit"
responses:
"200":
description: Paginated list of run events
content:
application/json:
schema:
$ref: "#/components/schemas/PaginatedEventList"
"404":
description: Run not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
post:
operationId: appendRunEvent
tags: [Run Internals]
summary: Append Run Event
description: Appends a validated event to the run event log. Intended for trusted internal callers.
parameters:
- $ref: "#/components/parameters/RunId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RunEvent"
responses:
"200":
description: Event appended
content:
application/json:
schema:
$ref: "#/components/schemas/AppendEventResponse"
"400":
description: Invalid event payload
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Run not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/attach:
get:
operationId: attachRunEvents
tags: [Run Internals]
summary: Attach Run Events
description: Opens a server-sent event stream for a live run. Optionally replays stored events from `since_seq` before switching to live updates.
parameters:
- $ref: "#/components/parameters/RunId"
- $ref: "#/components/parameters/SinceSeq"
responses:
"200":
description: Server-sent event stream
@ -357,7 +436,60 @@ paths:
schema:
$ref: "#/components/schemas/ErrorResponse"
"410":
description: Event stream closed
description: Run is not live on this server
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/blobs:
post:
operationId: writeRunBlob
tags: [Run Internals]
summary: Write Run Blob
description: Writes an opaque binary blob and returns its content-addressed blob identifier.
parameters:
- $ref: "#/components/parameters/RunId"
requestBody:
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
"200":
description: Blob written
content:
application/json:
schema:
$ref: "#/components/schemas/WriteBlobResponse"
"404":
description: Run not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/blobs/{blobId}:
get:
operationId: readRunBlob
tags: [Run Internals]
summary: Read Run Blob
description: Reads a previously stored blob by identifier.
parameters:
- $ref: "#/components/parameters/RunId"
- $ref: "#/components/parameters/BlobId"
responses:
"200":
description: Blob contents
content:
application/octet-stream:
schema:
type: string
format: binary
"404":
description: Run or blob not found
content:
application/json:
schema:
@ -497,6 +629,91 @@ paths:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/stages/{stageId}/artifacts:
get:
operationId: listStageArtifacts
tags: [Run Internals]
summary: List Stage Artifacts
description: Lists artifact filenames stored for a stage.
parameters:
- $ref: "#/components/parameters/RunId"
- $ref: "#/components/parameters/StageId"
responses:
"200":
description: Artifact filenames for the stage
content:
application/json:
schema:
$ref: "#/components/schemas/ArtifactListResponse"
"404":
description: Run not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
post:
operationId: putStageArtifact
tags: [Run Internals]
summary: Put Stage Artifact
description: Uploads an artifact for a stage. Intended for trusted internal callers.
parameters:
- $ref: "#/components/parameters/RunId"
- $ref: "#/components/parameters/StageId"
- $ref: "#/components/parameters/ArtifactFilename"
requestBody:
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
"204":
description: Artifact written
"400":
description: Missing filename
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Run not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/stages/{stageId}/artifacts/download:
get:
operationId: getStageArtifact
tags: [Run Internals]
summary: Get Stage Artifact
description: Downloads an artifact by filename.
parameters:
- $ref: "#/components/parameters/RunId"
- $ref: "#/components/parameters/StageId"
- $ref: "#/components/parameters/ArtifactFilename"
responses:
"200":
description: Artifact contents
content:
application/octet-stream:
schema:
type: string
format: binary
"400":
description: Missing filename
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Run, stage, or artifact not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/api/v1/runs/{id}/files:
get:
operationId: retrieveRunFiles
@ -1318,10 +1535,52 @@ components:
name: stageId
in: path
required: true
description: Identifier of a stage within a run's workflow graph.
description: Identifier of a stage within a run's workflow graph, serialized as `node_id@visit`.
schema:
type: string
example: propose-changes
example: code@2
BlobId:
name: blobId
in: path
required: true
description: Content-addressed blob identifier.
schema:
type: string
format: uuid
example: 550e8400-e29b-41d4-a716-446655440000
ArtifactFilename:
name: filename
in: query
required: true
description: Artifact filename. May contain path separators.
schema:
type: string
example: src/lib.rs
SinceSeq:
name: since_seq
in: query
required: false
description: First event sequence number to include.
schema:
type: integer
minimum: 1
default: 1
example: 42
EventLimit:
name: limit
in: query
required: false
description: Maximum number of events to return.
schema:
type: integer
minimum: 1
maximum: 1000
default: 100
example: 100
QuestionId:
name: qid
@ -2076,6 +2335,291 @@ components:
items:
$ref: "#/components/schemas/ErrorResponseEntry"
RunEvent:
description: >
Internal RunEvent-compatible JSON payload. The server validates this
body by deserializing into the typed RunEvent struct.
type: object
required:
- id
- ts
- run_id
- event
properties:
id:
type: string
ts:
type: string
format: date-time
run_id:
type: string
node_id:
type: string
nullable: true
node_label:
type: string
nullable: true
session_id:
type: string
nullable: true
parent_session_id:
type: string
nullable: true
event:
type: string
description: Event type discriminator.
example: stage.started
properties:
type: object
additionalProperties: true
additionalProperties: true
EventEnvelope:
description: Stored event envelope with assigned sequence number.
type: object
required:
- seq
- payload
properties:
seq:
type: integer
description: Assigned event sequence number.
example: 42
payload:
$ref: "#/components/schemas/RunEvent"
PaginatedEventList:
description: Paginated list of stored run events.
type: object
required:
- data
- meta
properties:
data:
type: array
items:
$ref: "#/components/schemas/EventEnvelope"
meta:
$ref: "#/components/schemas/PaginationMeta"
AppendEventResponse:
description: Assigned sequence number for an appended event.
type: object
required:
- seq
properties:
seq:
type: integer
description: Assigned event sequence number.
example: 42
WriteBlobResponse:
description: Content-addressed identifier for a stored blob.
type: object
required:
- id
properties:
id:
type: string
description: Blob identifier.
example: 550e8400-e29b-41d4-a716-446655440000
ArtifactEntry:
description: A single artifact filename.
type: object
required:
- filename
properties:
filename:
type: string
description: Artifact filename.
example: src/lib.rs
ArtifactListResponse:
description: List of artifact filenames for a stage.
type: object
required:
- data
properties:
data:
type: array
items:
$ref: "#/components/schemas/ArtifactEntry"
InternalRunStatus:
description: Internal event-sourced run status.
type: string
enum:
- submitted
- starting
- running
- paused
- removing
- succeeded
- failed
- dead
StatusReason:
description: Optional reason attached to a run status transition.
type: string
enum:
- completed
- partial_success
- workflow_error
- cancelled
- terminated
- transient_infra
- budget_exhausted
- launch_failed
- bootstrap_failed
- sandbox_init_failed
- sandbox_initializing
RunStatusRecord:
description: Internal run status record from the event projection.
type: object
required:
- status
- updated_at
properties:
status:
$ref: "#/components/schemas/InternalRunStatus"
reason:
oneOf:
- $ref: "#/components/schemas/StatusReason"
- type: "null"
updated_at:
type: string
format: date-time
InternalStageStatus:
description: Internal stage status from outcomes and node status records.
type: string
enum:
- success
- fail
- skipped
- partial_success
- retry
NodeStatusRecord:
description: Internal node status record.
type: object
required:
- status
- timestamp
properties:
status:
$ref: "#/components/schemas/InternalStageStatus"
notes:
type: string
nullable: true
failure_reason:
type: string
nullable: true
timestamp:
type: string
format: date-time
NodeState:
description: Internal node projection state.
type: object
properties:
prompt:
type: string
nullable: true
response:
type: string
nullable: true
status:
oneOf:
- $ref: "#/components/schemas/NodeStatusRecord"
- type: "null"
provider_used:
nullable: true
diff:
type: string
nullable: true
script_invocation:
nullable: true
script_timing:
nullable: true
parallel_results:
nullable: true
stdout:
type: string
nullable: true
stderr:
type: string
nullable: true
RunProjection:
description: Raw internal run projection derived from the event log.
type: object
required:
- nodes
properties:
run:
type: object
additionalProperties: true
nullable: true
graph_source:
type: string
nullable: true
start:
type: object
additionalProperties: true
nullable: true
status:
oneOf:
- $ref: "#/components/schemas/RunStatusRecord"
- type: "null"
checkpoint:
oneOf:
- $ref: "#/components/schemas/RunCheckpoint"
- type: "null"
checkpoints:
type: array
description: Sequence-tagged checkpoint history entries as `[seq, checkpoint]`.
items:
type: array
minItems: 2
maxItems: 2
items:
oneOf:
- type: integer
- $ref: "#/components/schemas/RunCheckpoint"
conclusion:
type: object
additionalProperties: true
nullable: true
retro:
type: object
additionalProperties: true
nullable: true
retro_prompt:
type: string
nullable: true
retro_response:
type: string
nullable: true
sandbox:
type: object
additionalProperties: true
nullable: true
final_patch:
type: string
nullable: true
pull_request:
type: object
additionalProperties: true
nullable: true
nodes:
type: object
description: Map from StageId (`node_id@visit`) to NodeState.
additionalProperties:
$ref: "#/components/schemas/NodeState"
# ── Run Board Schemas ────────────────────────────────────────────────
BoardColumn:

View file

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;
@ -13,14 +14,15 @@ use axum::response::{IntoResponse, Response};
use axum::routing::{get, post};
use axum::{Json, Router};
use axum_extra::extract::cookie::Key;
use bytes::Bytes;
use fabro_llm::client::Client as LlmClient;
use fabro_llm::generate::{GenerateParams, generate, generate_object};
use fabro_llm::types::{
ContentPart, FinishReason, Message as LlmMessage, Request as LlmRequest,
Response as LlmResponse, Role, StreamEvent, ToolChoice, ToolDefinition, Usage,
};
use fabro_store::StoreHandle;
use fabro_types::{RunEvent, RunId, Settings};
use fabro_store::{EventEnvelope, EventPayload, StageId, StoreHandle};
use fabro_types::{RunBlobId, RunEvent, RunId, Settings};
use fabro_util::redact::redact_jsonl_line;
use fabro_workflow::error::FabroError;
use fabro_workflow::handler::HandlerRegistry;
@ -32,7 +34,6 @@ use tokio::sync::{Notify, OnceCell};
use tokio::task::spawn_blocking;
use tokio::time::{sleep, timeout};
use tokio_stream::StreamExt;
use tokio_stream::wrappers::BroadcastStream;
use tower::{ServiceExt, service_fn};
use ulid::Ulid;
@ -53,11 +54,13 @@ use fabro_workflow::records::Checkpoint;
use fabro_api::types::AggregateUsageTotals;
pub use fabro_api::types::{
AggregateUsage, ApiQuestion, ApiQuestionOption, CompletionContentPart, CompletionMessage,
CompletionMessageRole, CompletionResponse, CompletionToolChoiceMode, CompletionUsage,
CreateCompletionRequest, CreateRunRequest, ModelReference, PaginatedRunList, PaginationMeta,
QuestionType as ApiQuestionType, RunError, RunStatus, RunStatusResponse, SubmitAnswerRequest,
TokenUsage, UsageByModel,
AggregateUsage, ApiQuestion, ApiQuestionOption, AppendEventResponse, ArtifactEntry,
ArtifactListResponse, CompletionContentPart, CompletionMessage, CompletionMessageRole,
CompletionResponse, CompletionToolChoiceMode, CompletionUsage, CreateCompletionRequest,
CreateRunRequest, EventEnvelope as ApiEventEnvelope, ModelReference, PaginatedEventList,
PaginatedRunList, PaginationMeta, QuestionType as ApiQuestionType, RunError, RunEvent as ApiRunEvent,
RunStatus, RunStatusResponse, SubmitAnswerRequest, TokenUsage, UsageByModel,
WriteBlobResponse,
};
pub fn default_page_limit() -> u32 {
@ -72,6 +75,36 @@ pub struct PaginationParams {
pub offset: u32,
}
#[derive(serde::Deserialize)]
struct EventListParams {
#[serde(default)]
since_seq: Option<u32>,
#[serde(default)]
limit: Option<usize>,
}
impl EventListParams {
fn since_seq(&self) -> u32 {
self.since_seq.unwrap_or(1).max(1)
}
fn limit(&self) -> usize {
self.limit.unwrap_or(100).clamp(1, 1000)
}
}
#[derive(serde::Deserialize)]
struct AttachParams {
#[serde(default)]
since_seq: Option<u32>,
}
#[derive(serde::Deserialize)]
struct ArtifactFilenameParams {
#[serde(default)]
filename: Option<String>,
}
/// Non-paginated list response wrapper with `has_more: false`.
#[derive(serde::Serialize)]
pub struct ListResponse<T: serde::Serialize> {
@ -199,7 +232,11 @@ fn demo_routes() -> Router<Arc<AppState>> {
.route("/runs/{id}", get(demo::get_run_status))
.route("/runs/{id}/questions", get(demo::get_questions_stub))
.route("/runs/{id}/questions/{qid}/answer", post(demo::answer_stub))
.route("/runs/{id}/events", get(demo::run_events_stub))
.route("/runs/{id}/state", get(not_implemented))
.route("/runs/{id}/events", get(not_implemented).post(not_implemented))
.route("/runs/{id}/attach", get(demo::run_events_stub))
.route("/runs/{id}/blobs", post(not_implemented))
.route("/runs/{id}/blobs/{blobId}", get(not_implemented))
.route("/runs/{id}/checkpoint", get(demo::checkpoint_stub))
.route("/runs/{id}/cancel", post(demo::cancel_stub))
.route("/runs/{id}/start", post(demo::start_run_stub))
@ -212,6 +249,14 @@ fn demo_routes() -> Router<Arc<AppState>> {
"/runs/{id}/stages/{stageId}/turns",
get(demo::get_stage_turns),
)
.route(
"/runs/{id}/stages/{stageId}/artifacts",
get(not_implemented).post(not_implemented),
)
.route(
"/runs/{id}/stages/{stageId}/artifacts/download",
get(not_implemented),
)
.route("/runs/{id}/files", get(demo::get_run_files))
.route("/runs/{id}/usage", get(demo::get_run_usage))
.route("/runs/{id}/verification", get(demo::get_run_verification))
@ -275,7 +320,11 @@ fn real_routes() -> Router<Arc<AppState>> {
.route("/runs/{id}", get(get_run_status))
.route("/runs/{id}/questions", get(get_questions))
.route("/runs/{id}/questions/{qid}/answer", post(submit_answer))
.route("/runs/{id}/events", get(get_events))
.route("/runs/{id}/state", get(get_run_state))
.route("/runs/{id}/events", get(list_run_events).post(append_run_event))
.route("/runs/{id}/attach", get(attach_run_events))
.route("/runs/{id}/blobs", post(write_run_blob))
.route("/runs/{id}/blobs/{blobId}", get(read_run_blob))
.route("/runs/{id}/checkpoint", get(get_checkpoint))
.route("/runs/{id}/cancel", post(cancel_run))
.route("/runs/{id}/start", post(start_run))
@ -285,6 +334,14 @@ fn real_routes() -> Router<Arc<AppState>> {
.route("/runs/{id}/retro", get(get_retro))
.route("/runs/{id}/stages", get(not_implemented))
.route("/runs/{id}/stages/{stageId}/turns", get(not_implemented))
.route(
"/runs/{id}/stages/{stageId}/artifacts",
get(list_stage_artifacts).post(put_stage_artifact),
)
.route(
"/runs/{id}/stages/{stageId}/artifacts/download",
get(get_stage_artifact),
)
.route("/runs/{id}/files", get(not_implemented))
.route("/runs/{id}/usage", get(not_implemented))
.route("/runs/{id}/verification", get(not_implemented))
@ -521,6 +578,54 @@ fn parse_run_id_path(id: &str) -> Result<RunId, Response> {
.map_err(|_| ApiError::bad_request("Invalid run ID.").into_response())
}
#[allow(clippy::result_large_err)]
fn parse_stage_id_path(stage_id: &str) -> Result<StageId, Response> {
StageId::from_str(stage_id)
.map_err(|_| ApiError::bad_request("Invalid stage ID.").into_response())
}
#[allow(clippy::result_large_err)]
fn parse_blob_id_path(blob_id: &str) -> Result<RunBlobId, Response> {
RunBlobId::from_str(blob_id)
.map_err(|_| ApiError::bad_request("Invalid blob ID.").into_response())
}
#[allow(clippy::result_large_err)]
fn required_filename(params: ArtifactFilenameParams) -> Result<String, Response> {
match params.filename {
Some(filename) if !filename.is_empty() => Ok(filename),
_ => Err(ApiError::bad_request("Missing filename query parameter.").into_response()),
}
}
fn octet_stream_response(bytes: Bytes) -> Response {
(
StatusCode::OK,
[("content-type", "application/octet-stream")],
bytes,
)
.into_response()
}
#[allow(clippy::result_large_err)]
fn api_run_event_from_store(payload: &EventPayload) -> Result<ApiRunEvent, Response> {
serde_json::from_value(payload.as_value().clone()).map_err(|err| {
ApiError::new(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to serialize stored event: {err}"),
)
.into_response()
})
}
#[allow(clippy::result_large_err)]
fn api_event_envelope_from_store(event: &EventEnvelope) -> Result<ApiEventEnvelope, Response> {
Ok(ApiEventEnvelope {
payload: api_run_event_from_store(&event.payload)?,
seq: i64::from(event.seq),
})
}
fn clear_live_run_state(run: &mut ManagedRun) {
run.interviewer = None;
run.event_tx = None;
@ -1033,7 +1138,7 @@ async fn submit_answer(
}
}
async fn get_events(
async fn get_run_state(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
@ -1042,28 +1147,144 @@ async fn get_events(
Ok(id) => id,
Err(response) => return response,
};
let rx = {
let runs = state.runs.lock().expect("runs lock poisoned");
match runs.get(&id) {
Some(managed_run) => match &managed_run.event_tx {
Some(tx) => tx.subscribe(),
None => {
return ApiError::new(StatusCode::GONE, "Event stream closed.").into_response();
}
},
None => return ApiError::not_found("Run not found.").into_response(),
}
match state.store.open_run_reader(&id).await {
Ok(run_store) => match run_store.state().await {
Ok(run_state) => Json(run_state).into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn append_run_event(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
Json(value): Json<serde_json::Value>,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
let event = match RunEvent::from_value(value.clone()) {
Ok(event) => event,
Err(err) => return ApiError::bad_request(format!("Invalid run event: {err}")).into_response(),
};
if event.run_id != id {
return ApiError::bad_request("Event run_id does not match path run ID.").into_response();
}
let payload = match EventPayload::new(value, &id) {
Ok(payload) => payload,
Err(err) => return ApiError::bad_request(err.to_string()).into_response(),
};
let stream = BroadcastStream::new(rx).filter_map(|result| match result {
Ok(event) => {
let data = serde_json::to_string(&event).unwrap_or_default();
let data = redact_jsonl_line(&data);
Some(Ok::<Event, std::convert::Infallible>(
Event::default().data(data),
))
match state.store.open_run(&id).await {
Ok(run_store) => match run_store.append_event(&payload).await {
Ok(seq) => Json(AppendEventResponse { seq: i64::from(seq) }).into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn list_run_events(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
Query(params): Query<EventListParams>,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
let since_seq = params.since_seq();
let limit = params.limit();
match state.store.open_run_reader(&id).await {
Ok(run_store) => match run_store.list_events_from_with_limit(since_seq, limit).await {
Ok(mut events) => {
let has_more = events.len() > limit;
events.truncate(limit);
let mut data = Vec::with_capacity(events.len());
for event in events {
let event = match api_event_envelope_from_store(&event) {
Ok(event) => event,
Err(response) => return response,
};
data.push(event);
}
Json(PaginatedEventList {
data,
meta: PaginationMeta { has_more },
})
.into_response()
}
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn attach_run_events(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
Query(params): Query<AttachParams>,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
{
let runs = state.runs.lock().expect("runs lock poisoned");
let Some(managed_run) = runs.get(&id) else {
return ApiError::not_found("Run not found.").into_response();
};
if !matches!(
managed_run.status,
RunStatus::Queued | RunStatus::Starting | RunStatus::Running | RunStatus::Paused
) {
return ApiError::new(StatusCode::GONE, "Run is not live on this server.")
.into_response();
}
}
let Ok(run_store) = state.store.open_run_reader(&id).await else {
return ApiError::not_found("Run not found.").into_response();
};
let start_seq = match params.since_seq {
Some(seq) if seq >= 1 => seq,
Some(_) => 1,
None => match run_store.list_events().await {
Ok(events) => events.last().map_or(1, |event| event.seq.saturating_add(1)),
Err(err) => {
return ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response();
}
},
};
let stream = match run_store.watch_events_from(start_seq) {
Ok(stream) => stream,
Err(err) => {
return ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response();
}
};
let stream = stream.filter_map(|result| {
match result {
Ok(event) => {
let event = api_event_envelope_from_store(&event).ok()?;
let data = serde_json::to_string(&event).ok()?;
let data = redact_jsonl_line(&data);
Some(Ok::<Event, std::convert::Infallible>(
Event::default().data(data),
))
}
Err(_) => None,
}
Err(_) => None,
});
Sse::new(stream).into_response()
@ -1107,6 +1328,140 @@ async fn get_checkpoint(
}
}
async fn write_run_blob(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
body: Bytes,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
match state.store.open_run(&id).await {
Ok(run_store) => match run_store.write_blob(&body).await {
Ok(blob_id) => Json(WriteBlobResponse {
id: blob_id.to_string(),
})
.into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn read_run_blob(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path((id, blob_id)): Path<(String, String)>,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
let blob_id = match parse_blob_id_path(&blob_id) {
Ok(blob_id) => blob_id,
Err(response) => return response,
};
match state.store.open_run_reader(&id).await {
Ok(run_store) => match run_store.read_blob(&blob_id).await {
Ok(Some(bytes)) => octet_stream_response(bytes),
Ok(None) => ApiError::not_found("Blob not found.").into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn list_stage_artifacts(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path((id, stage_id)): Path<(String, String)>,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
let stage_id = match parse_stage_id_path(&stage_id) {
Ok(stage_id) => stage_id,
Err(response) => return response,
};
match state.store.open_run_reader(&id).await {
Ok(run_store) => match run_store.list_artifacts_for_stage(&stage_id).await {
Ok(filenames) => Json(ArtifactListResponse {
data: filenames
.into_iter()
.map(|filename| ArtifactEntry { filename })
.collect(),
})
.into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn put_stage_artifact(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path((id, stage_id)): Path<(String, String)>,
Query(params): Query<ArtifactFilenameParams>,
body: Bytes,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
let stage_id = match parse_stage_id_path(&stage_id) {
Ok(stage_id) => stage_id,
Err(response) => return response,
};
let filename = match required_filename(params) {
Ok(filename) => filename,
Err(response) => return response,
};
match state.store.open_run(&id).await {
Ok(run_store) => match run_store.put_artifact(&stage_id, &filename, &body).await {
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn get_stage_artifact(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
Path((id, stage_id)): Path<(String, String)>,
Query(params): Query<ArtifactFilenameParams>,
) -> Response {
let id = match parse_run_id_path(&id) {
Ok(id) => id,
Err(response) => return response,
};
let stage_id = match parse_stage_id_path(&stage_id) {
Ok(stage_id) => stage_id,
Err(response) => return response,
};
let filename = match required_filename(params) {
Ok(filename) => filename,
Err(response) => return response,
};
match state.store.open_run_reader(&id).await {
Ok(run_store) => match run_store.get_artifact(&stage_id, &filename).await {
Ok(Some(bytes)) => octet_stream_response(bytes),
Ok(None) => ApiError::not_found("Artifact not found.").into_response(),
Err(err) => ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
.into_response(),
},
Err(_) => ApiError::not_found("Run not found.").into_response(),
}
}
async fn cancel_run(
_auth: AuthenticatedService,
State(state): State<Arc<AppState>>,
@ -2031,6 +2386,105 @@ mod tests {
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn get_run_state_returns_projection() {
let state = create_app_state();
let app = build_router(Arc::clone(&state), AuthMode::Disabled);
let req = Request::builder()
.method("POST")
.uri(api("/runs"))
.header("content-type", "application/json")
.body(Body::from(
serde_json::to_string(&serde_json::json!({"dot_source": MINIMAL_DOT})).unwrap(),
))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
let body = body_json(response.into_body()).await;
let run_id = body["id"].as_str().unwrap();
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/state")))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = body_json(response.into_body()).await;
assert!(body["nodes"].is_object());
}
#[tokio::test]
async fn list_run_events_returns_paginated_json() {
let state = create_app_state();
let app = build_router(Arc::clone(&state), AuthMode::Disabled);
let req = Request::builder()
.method("POST")
.uri(api("/runs"))
.header("content-type", "application/json")
.body(Body::from(
serde_json::to_string(&serde_json::json!({"dot_source": MINIMAL_DOT})).unwrap(),
))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
let body = body_json(response.into_body()).await;
let run_id = body["id"].as_str().unwrap();
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/events?since_seq=1&limit=5")))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = body_json(response.into_body()).await;
assert!(body["data"].is_array());
assert!(body["meta"]["has_more"].is_boolean());
}
#[tokio::test]
async fn append_run_event_rejects_run_id_mismatch() {
let state = create_app_state();
let app = build_router(Arc::clone(&state), AuthMode::Disabled);
let req = Request::builder()
.method("POST")
.uri(api("/runs"))
.header("content-type", "application/json")
.body(Body::from(
serde_json::to_string(&serde_json::json!({"dot_source": MINIMAL_DOT})).unwrap(),
))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
let body = body_json(response.into_body()).await;
let run_id = body["id"].as_str().unwrap();
let req = Request::builder()
.method("POST")
.uri(api(&format!("/runs/{run_id}/events")))
.header("content-type", "application/json")
.body(Body::from(
serde_json::json!({
"id": "evt-test",
"ts": "2026-03-27T12:00:00Z",
"run_id": fixtures::RUN_64.to_string(),
"event": "run.submitted",
"properties": {}
})
.to_string(),
))
.unwrap();
let response = app.oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}
#[tokio::test]
async fn get_checkpoint_returns_null_initially() {
let state = create_app_state();
@ -2061,6 +2515,99 @@ mod tests {
assert_eq!(response.status(), StatusCode::OK);
}
#[tokio::test]
async fn write_and_read_run_blob_round_trip() {
let state = create_app_state();
let app = build_router(Arc::clone(&state), AuthMode::Disabled);
let req = Request::builder()
.method("POST")
.uri(api("/runs"))
.header("content-type", "application/json")
.body(Body::from(
serde_json::to_string(&serde_json::json!({"dot_source": MINIMAL_DOT})).unwrap(),
))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
let body = body_json(response.into_body()).await;
let run_id = body["id"].as_str().unwrap();
let req = Request::builder()
.method("POST")
.uri(api(&format!("/runs/{run_id}/blobs")))
.header("content-type", "application/octet-stream")
.body(Body::from("hello blob"))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = body_json(response.into_body()).await;
let blob_id = body["id"].as_str().unwrap();
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/blobs/{blob_id}")))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let bytes = to_bytes(response.into_body(), usize::MAX).await.unwrap();
assert_eq!(&bytes[..], b"hello blob");
}
#[tokio::test]
async fn stage_artifacts_round_trip() {
let state = create_app_state();
let app = build_router(Arc::clone(&state), AuthMode::Disabled);
let req = Request::builder()
.method("POST")
.uri(api("/runs"))
.header("content-type", "application/json")
.body(Body::from(
serde_json::to_string(&serde_json::json!({"dot_source": MINIMAL_DOT})).unwrap(),
))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
let body = body_json(response.into_body()).await;
let run_id = body["id"].as_str().unwrap();
let stage_id = "code@2";
let req = Request::builder()
.method("POST")
.uri(api(&format!(
"/runs/{run_id}/stages/{stage_id}/artifacts?filename=src/lib.rs"
)))
.header("content-type", "application/octet-stream")
.body(Body::from("fn main() {}"))
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::NO_CONTENT);
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/stages/{stage_id}/artifacts")))
.body(Body::empty())
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = body_json(response.into_body()).await;
assert_eq!(body["data"][0]["filename"], "src/lib.rs");
let req = Request::builder()
.method("GET")
.uri(api(&format!(
"/runs/{run_id}/stages/{stage_id}/artifacts/download?filename=src/lib.rs"
)))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let bytes = to_bytes(response.into_body(), usize::MAX).await.unwrap();
assert_eq!(&bytes[..], b"fn main() {}");
}
#[tokio::test]
async fn create_run_returns_submitted() {
let state = create_app_state();
@ -2198,25 +2745,23 @@ mod tests {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn get_events_returns_sse_stream() {
async fn attach_run_events_returns_sse_stream() {
let state = create_app_state();
let app = test_app_with_scheduler(state);
let run_id_str = create_and_start_run(&app, MINIMAL_DOT).await;
let run_id = run_id_str.parse::<RunId>().unwrap();
// Wait for scheduler to promote run (creates event_tx)
// Wait for scheduler to promote run.
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
// Request the SSE stream
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/events")))
.uri(api(&format!("/runs/{run_id}/attach")))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
// May be 200 (stream open) or 410 (run completed before we connect)
let status = response.status();
assert!(
status == StatusCode::OK || status == StatusCode::GONE,
@ -2714,7 +3259,7 @@ mod tests {
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/events")))
.uri(api(&format!("/runs/{run_id}/attach")))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();

View file

@ -757,7 +757,7 @@ mod sse_events {
// Get SSE stream
let req = Request::builder()
.method("GET")
.uri(api(&format!("/runs/{run_id}/events")))
.uri(api(&format!("/runs/{run_id}/attach")))
.body(Body::empty())
.unwrap();
let response = app.clone().oneshot(req).await.unwrap();
@ -796,7 +796,7 @@ mod sse_events {
if let Some(json_str) = line.strip_prefix("data:") {
let json_str = json_str.trim();
if let Ok(event) = serde_json::from_str::<serde_json::Value>(json_str) {
if let Some(event_name) = event["event"].as_str() {
if let Some(event_name) = event["payload"]["event"].as_str() {
event_types.push(event_name.to_string());
}
}

View file

@ -16,7 +16,7 @@ use fabro_types::{
SandboxRecord, StageStatus, StageUsage, StartRecord, StatusReason, TokenUsage,
};
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, serde::Serialize)]
pub struct RunProjection {
pub run: Option<RunRecord>,
pub graph_source: Option<String>,
@ -34,7 +34,7 @@ pub struct RunProjection {
nodes: HashMap<StageId, NodeState>,
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, serde::Serialize)]
pub struct NodeState {
pub prompt: Option<String>,
pub response: Option<String>,

View file

@ -1231,6 +1231,57 @@ mod tests {
);
}
#[tokio::test]
async fn slate_run_store_lists_events_with_limit() {
let (_object_store, store) = make_store();
let run = store.create_run(&test_run_id("run-1")).await.unwrap();
for (idx, ts) in [
"2026-03-27T12:00:00Z",
"2026-03-27T12:00:01Z",
"2026-03-27T12:00:02Z",
]
.into_iter()
.enumerate()
{
run.append_event(&event_payload(
"run-1",
ts,
"run.submitted",
None,
serde_json::json!({"index": idx}),
))
.await
.unwrap();
}
let events = run.list_events_from_with_limit(2, 1).await.unwrap();
assert_eq!(events.iter().map(|event| event.seq).collect::<Vec<_>>(), vec![2, 3]);
}
#[tokio::test]
async fn slate_run_store_lists_artifacts_for_stage_only() {
let (_object_store, store) = make_store();
let run = store.create_run(&test_run_id("run-1")).await.unwrap();
let code_stage = StageId::new("code", 2);
let build_stage = StageId::new("build", 1);
run.put_artifact(&code_stage, "src/lib.rs", b"fn main() {}")
.await
.unwrap();
run.put_artifact(&code_stage, "src/main.rs", b"fn main() {}")
.await
.unwrap();
run.put_artifact(&build_stage, "target/output.txt", b"ok")
.await
.unwrap();
assert_eq!(
run.list_artifacts_for_stage(&code_stage).await.unwrap(),
vec!["src/lib.rs".to_string(), "src/main.rs".to_string()]
);
}
#[tokio::test]
async fn create_run_state_and_node_storage_round_trip() {
let (_object_store, store) = make_store();

View file

@ -175,6 +175,17 @@ impl SlateRunStore {
self.inner.db.list_events_from(1).await
}
pub async fn list_events_from_with_limit(
&self,
start_seq: u32,
limit: usize,
) -> Result<Vec<EventEnvelope>> {
self.inner
.db
.list_events_from_with_limit(start_seq, limit)
.await
}
pub fn watch_events_from(
&self,
seq: u32,
@ -245,6 +256,10 @@ impl SlateRunStore {
self.inner.db.list_all_artifacts().await
}
pub async fn list_artifacts_for_stage(&self, stage_id: &StageId) -> Result<Vec<String>> {
self.inner.db.list_artifacts_for_stage(stage_id).await
}
pub async fn state(&self) -> Result<RunProjection> {
self.projected_state().await
}
@ -287,6 +302,17 @@ impl SlateRunDb {
}
}
async fn list_events_from_with_limit(
&self,
start_seq: u32,
limit: usize,
) -> Result<Vec<EventEnvelope>> {
match self {
Self::Writer(db) => list_events_from_with_limit(db, start_seq, limit).await,
Self::Reader(db) => list_events_from_with_limit(db.as_ref(), start_seq, limit).await,
}
}
async fn list_blobs(&self) -> Result<Vec<RunBlobId>> {
match self {
Self::Writer(db) => list_blobs(db).await,
@ -300,6 +326,13 @@ impl SlateRunDb {
Self::Reader(db) => list_all_artifacts(db.as_ref()).await,
}
}
async fn list_artifacts_for_stage(&self, stage_id: &StageId) -> Result<Vec<String>> {
match self {
Self::Writer(db) => list_artifacts_for_stage(db, stage_id).await,
Self::Reader(db) => list_artifacts_for_stage(db.as_ref(), stage_id).await,
}
}
}
async fn put_json<T: Serialize>(db: &slatedb::Db, key: &str, value: &T) -> Result<()> {
@ -366,6 +399,19 @@ where
Ok(events)
}
async fn list_events_from_with_limit<R>(
db: &R,
start_seq: u32,
limit: usize,
) -> Result<Vec<EventEnvelope>>
where
R: DbRead + Sync,
{
let mut events = list_events_from(db, start_seq).await?;
events.truncate(limit.saturating_add(1));
Ok(events)
}
async fn list_blobs<R>(db: &R) -> Result<Vec<RunBlobId>>
where
R: DbRead + Sync,
@ -402,6 +448,26 @@ where
Ok(assets)
}
async fn list_artifacts_for_stage<R>(db: &R, stage_id: &StageId) -> Result<Vec<String>>
where
R: DbRead + Sync,
{
let prefix = keys::node_artifact_prefix(stage_id);
let mut iter = db.scan_prefix(prefix.as_bytes()).await?;
let mut filenames = Vec::new();
while let Some(entry) = iter.next().await? {
let key = key_to_string(&entry.key)?;
let Some((node, filename)) = keys::parse_node_artifact_key(&key) else {
continue;
};
if &node == stage_id {
filenames.push(filename);
}
}
filenames.sort();
Ok(filenames)
}
fn key_to_string(key: &Bytes) -> Result<String> {
String::from_utf8(key.to_vec())
.map_err(|err| StoreError::Other(format!("stored key is not valid UTF-8: {err}")))

View file

@ -22,6 +22,9 @@ models/aggregate-usage.ts
models/api-question-option.ts
models/api-question.ts
models/api-settings.ts
models/append-event-response.ts
models/artifact-entry.ts
models/artifact-list-response.ts
models/artifacts-settings.ts
models/assistant-stage-turn.ts
models/assistant-turn.ts
@ -55,6 +58,7 @@ models/diff-file.ts
models/diff-stats.ts
models/error-response-entry.ts
models/error-response.ts
models/event-envelope.ts
models/execute-query-request.ts
models/execute-query-response-rows-inner-inner.ts
models/execute-query-response.ts
@ -70,6 +74,8 @@ models/health-response.ts
models/history-entry.ts
models/hook-definition.ts
models/index.ts
models/internal-run-status.ts
models/internal-stage-status.ts
models/learning-category.ts
models/learning.ts
models/llm-settings.ts
@ -82,9 +88,12 @@ models/model-limits.ts
models/model-reference.ts
models/model-test-result.ts
models/model.ts
models/node-state.ts
models/node-status-record.ts
models/open-item-kind.ts
models/open-item.ts
models/paginated-api-question-list.ts
models/paginated-event-list.ts
models/paginated-history-entry-list.ts
models/paginated-model-list.ts
models/paginated-retro-list.ts
@ -113,13 +122,17 @@ models/root-response-urls.ts
models/root-response.ts
models/run-checkpoint.ts
models/run-error.ts
models/run-event.ts
models/run-list-item.ts
models/run-projection-checkpoints-inner-inner.ts
models/run-projection.ts
models/run-pull-request.ts
models/run-question.ts
models/run-reference.ts
models/run-sandbox.ts
models/run-settings.ts
models/run-stage.ts
models/run-status-record.ts
models/run-status-response.ts
models/run-status.ts
models/run-timings.ts
@ -144,6 +157,7 @@ models/smoothness-rating.ts
models/stage-retro.ts
models/stage-status.ts
models/stage-turn.ts
models/status-reason.ts
models/steer-request.ts
models/submit-answer-request.ts
models/system-stage-turn.ts
@ -173,3 +187,4 @@ models/workflow-last-run.ts
models/workflow-list-item.ts
models/workflow-reference.ts
models/workflow-schedule.ts
models/write-blob-response.ts

View file

@ -22,20 +22,268 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base';
// @ts-ignore
import type { AppendEventResponse } from '../models';
// @ts-ignore
import type { ArtifactListResponse } from '../models';
// @ts-ignore
import type { ErrorResponse } from '../models';
// @ts-ignore
import type { PaginatedEventList } from '../models';
// @ts-ignore
import type { PaginatedRunStageList } from '../models';
// @ts-ignore
import type { PaginatedStageTurnList } from '../models';
// @ts-ignore
import type { RunCheckpoint } from '../models';
// @ts-ignore
import type { RunEvent } from '../models';
// @ts-ignore
import type { RunProjection } from '../models';
// @ts-ignore
import type { RunSettings } from '../models';
// @ts-ignore
import type { WriteBlobResponse } from '../models';
/**
* RunInternalsApi - axios parameter creator
*/
export const RunInternalsApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
* Appends a validated event to the run event log. Intended for trusted internal callers.
* @summary Append Run Event
* @param {string} id Unique run identifier (ULID).
* @param {RunEvent} runEvent
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
appendRunEvent: async (id: string, runEvent: RunEvent, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('appendRunEvent', 'id', id)
// verify required parameter 'runEvent' is not null or undefined
assertParamExists('appendRunEvent', 'runEvent', runEvent)
const localVarPath = `/api/v1/runs/{id}/events`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Content-Type'] = 'application/json';
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(runEvent, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Opens a server-sent event stream for a live run. Optionally replays stored events from `since_seq` before switching to live updates.
* @summary Attach Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
attachRunEvents: async (id: string, sinceSeq?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('attachRunEvents', 'id', id)
const localVarPath = `/api/v1/runs/{id}/attach`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (sinceSeq !== undefined) {
localVarQueryParameter['since_seq'] = sinceSeq;
}
localVarHeaderParameter['Accept'] = 'text/event-stream,application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Returns the internal event-sourced run projection. This is not a stable public contract.
* @summary Get Run State
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getRunState: async (id: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('getRunState', 'id', id)
const localVarPath = `/api/v1/runs/{id}/state`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Downloads an artifact by filename.
* @summary Get Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getStageArtifact: async (id: string, stageId: string, filename: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('getStageArtifact', 'id', id)
// verify required parameter 'stageId' is not null or undefined
assertParamExists('getStageArtifact', 'stageId', stageId)
// verify required parameter 'filename' is not null or undefined
assertParamExists('getStageArtifact', 'filename', filename)
const localVarPath = `/api/v1/runs/{id}/stages/{stageId}/artifacts/download`
.replace(`{${"id"}}`, encodeURIComponent(String(id)))
.replace(`{${"stageId"}}`, encodeURIComponent(String(stageId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (filename !== undefined) {
localVarQueryParameter['filename'] = filename;
}
localVarHeaderParameter['Accept'] = 'application/octet-stream,application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Returns a paginated JSON list of stored run events.
* @summary List Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {number} [limit] Maximum number of events to return.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listRunEvents: async (id: string, sinceSeq?: number, limit?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('listRunEvents', 'id', id)
const localVarPath = `/api/v1/runs/{id}/events`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (sinceSeq !== undefined) {
localVarQueryParameter['since_seq'] = sinceSeq;
}
if (limit !== undefined) {
localVarQueryParameter['limit'] = limit;
}
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Returns the ordered list of stages in a run\'s workflow graph with their current status and timing. Stages are bounded by the workflow graph size, typically fewer than 20.
* @summary List Run Stages
@ -87,11 +335,56 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config
options: localVarRequestOptions,
};
},
/**
* Lists artifact filenames stored for a stage.
* @summary List Stage Artifacts
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listStageArtifacts: async (id: string, stageId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('listStageArtifacts', 'id', id)
// verify required parameter 'stageId' is not null or undefined
assertParamExists('listStageArtifacts', 'stageId', stageId)
const localVarPath = `/api/v1/runs/{id}/stages/{stageId}/artifacts`
.replace(`{${"id"}}`, encodeURIComponent(String(id)))
.replace(`{${"stageId"}}`, encodeURIComponent(String(stageId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Returns a paginated list of conversation turns within a specific stage, including system prompts, assistant responses, and tool invocations.
* @summary List Stage Turns
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph.
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {*} [options] Override http request option.
@ -142,6 +435,108 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config
options: localVarRequestOptions,
};
},
/**
* Uploads an artifact for a stage. Intended for trusted internal callers.
* @summary Put Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
putStageArtifact: async (id: string, stageId: string, filename: string, body: File, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('putStageArtifact', 'id', id)
// verify required parameter 'stageId' is not null or undefined
assertParamExists('putStageArtifact', 'stageId', stageId)
// verify required parameter 'filename' is not null or undefined
assertParamExists('putStageArtifact', 'filename', filename)
// verify required parameter 'body' is not null or undefined
assertParamExists('putStageArtifact', 'body', body)
const localVarPath = `/api/v1/runs/{id}/stages/{stageId}/artifacts`
.replace(`{${"id"}}`, encodeURIComponent(String(id)))
.replace(`{${"stageId"}}`, encodeURIComponent(String(stageId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (filename !== undefined) {
localVarQueryParameter['filename'] = filename;
}
localVarHeaderParameter['Content-Type'] = 'application/octet-stream';
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Reads a previously stored blob by identifier.
* @summary Read Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {string} blobId Content-addressed blob identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
readRunBlob: async (id: string, blobId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('readRunBlob', 'id', id)
// verify required parameter 'blobId' is not null or undefined
assertParamExists('readRunBlob', 'blobId', blobId)
const localVarPath = `/api/v1/runs/{id}/blobs/{blobId}`
.replace(`{${"id"}}`, encodeURIComponent(String(id)))
.replace(`{${"blobId"}}`, encodeURIComponent(String(blobId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Accept'] = 'application/octet-stream,application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Returns the latest checkpoint data for a run, or null if no checkpoint has been recorded yet.
* @summary Retrieve Run Checkpoint
@ -219,6 +614,52 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Writes an opaque binary blob and returns its content-addressed blob identifier.
* @summary Write Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
writeRunBlob: async (id: string, body: File, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('writeRunBlob', 'id', id)
// verify required parameter 'body' is not null or undefined
assertParamExists('writeRunBlob', 'body', body)
const localVarPath = `/api/v1/runs/{id}/blobs`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Content-Type'] = 'application/octet-stream';
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
@ -233,6 +674,77 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config
export const RunInternalsApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = RunInternalsApiAxiosParamCreator(configuration)
return {
/**
* Appends a validated event to the run event log. Intended for trusted internal callers.
* @summary Append Run Event
* @param {string} id Unique run identifier (ULID).
* @param {RunEvent} runEvent
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async appendRunEvent(id: string, runEvent: RunEvent, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AppendEventResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.appendRunEvent(id, runEvent, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.appendRunEvent']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Opens a server-sent event stream for a live run. Optionally replays stored events from `since_seq` before switching to live updates.
* @summary Attach Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async attachRunEvents(id: string, sinceSeq?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<string>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.attachRunEvents(id, sinceSeq, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.attachRunEvents']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Returns the internal event-sourced run projection. This is not a stable public contract.
* @summary Get Run State
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getRunState(id: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<RunProjection>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getRunState(id, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.getRunState']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Downloads an artifact by filename.
* @summary Get Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getStageArtifact(id: string, stageId: string, filename: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getStageArtifact(id, stageId, filename, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.getStageArtifact']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Returns a paginated JSON list of stored run events.
* @summary List Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {number} [limit] Maximum number of events to return.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listRunEvents(id: string, sinceSeq?: number, limit?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PaginatedEventList>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listRunEvents(id, sinceSeq, limit, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.listRunEvents']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Returns the ordered list of stages in a run\'s workflow graph with their current status and timing. Stages are bounded by the workflow graph size, typically fewer than 20.
* @summary List Run Stages
@ -248,11 +760,25 @@ export const RunInternalsApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.listRunStages']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Lists artifact filenames stored for a stage.
* @summary List Stage Artifacts
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listStageArtifacts(id: string, stageId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ArtifactListResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listStageArtifacts(id, stageId, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.listStageArtifacts']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Returns a paginated list of conversation turns within a specific stage, including system prompts, assistant responses, and tool invocations.
* @summary List Stage Turns
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph.
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {*} [options] Override http request option.
@ -264,6 +790,36 @@ export const RunInternalsApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.listStageTurns']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Uploads an artifact for a stage. Intended for trusted internal callers.
* @summary Put Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async putStageArtifact(id: string, stageId: string, filename: string, body: File, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.putStageArtifact(id, stageId, filename, body, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.putStageArtifact']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Reads a previously stored blob by identifier.
* @summary Read Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {string} blobId Content-addressed blob identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async readRunBlob(id: string, blobId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.readRunBlob(id, blobId, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.readRunBlob']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Returns the latest checkpoint data for a run, or null if no checkpoint has been recorded yet.
* @summary Retrieve Run Checkpoint
@ -290,6 +846,20 @@ export const RunInternalsApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.retrieveRunSettings']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Writes an opaque binary blob and returns its content-addressed blob identifier.
* @summary Write Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async writeRunBlob(id: string, body: File, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<WriteBlobResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.writeRunBlob(id, body, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.writeRunBlob']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
}
};
@ -299,6 +869,62 @@ export const RunInternalsApiFp = function(configuration?: Configuration) {
export const RunInternalsApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = RunInternalsApiFp(configuration)
return {
/**
* Appends a validated event to the run event log. Intended for trusted internal callers.
* @summary Append Run Event
* @param {string} id Unique run identifier (ULID).
* @param {RunEvent} runEvent
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
appendRunEvent(id: string, runEvent: RunEvent, options?: RawAxiosRequestConfig): AxiosPromise<AppendEventResponse> {
return localVarFp.appendRunEvent(id, runEvent, options).then((request) => request(axios, basePath));
},
/**
* Opens a server-sent event stream for a live run. Optionally replays stored events from `since_seq` before switching to live updates.
* @summary Attach Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
attachRunEvents(id: string, sinceSeq?: number, options?: RawAxiosRequestConfig): AxiosPromise<string> {
return localVarFp.attachRunEvents(id, sinceSeq, options).then((request) => request(axios, basePath));
},
/**
* Returns the internal event-sourced run projection. This is not a stable public contract.
* @summary Get Run State
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getRunState(id: string, options?: RawAxiosRequestConfig): AxiosPromise<RunProjection> {
return localVarFp.getRunState(id, options).then((request) => request(axios, basePath));
},
/**
* Downloads an artifact by filename.
* @summary Get Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getStageArtifact(id: string, stageId: string, filename: string, options?: RawAxiosRequestConfig): AxiosPromise<File> {
return localVarFp.getStageArtifact(id, stageId, filename, options).then((request) => request(axios, basePath));
},
/**
* Returns a paginated JSON list of stored run events.
* @summary List Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {number} [limit] Maximum number of events to return.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listRunEvents(id: string, sinceSeq?: number, limit?: number, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedEventList> {
return localVarFp.listRunEvents(id, sinceSeq, limit, options).then((request) => request(axios, basePath));
},
/**
* Returns the ordered list of stages in a run\'s workflow graph with their current status and timing. Stages are bounded by the workflow graph size, typically fewer than 20.
* @summary List Run Stages
@ -311,11 +937,22 @@ export const RunInternalsApiFactory = function (configuration?: Configuration, b
listRunStages(id: string, pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedRunStageList> {
return localVarFp.listRunStages(id, pageLimit, pageOffset, options).then((request) => request(axios, basePath));
},
/**
* Lists artifact filenames stored for a stage.
* @summary List Stage Artifacts
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listStageArtifacts(id: string, stageId: string, options?: RawAxiosRequestConfig): AxiosPromise<ArtifactListResponse> {
return localVarFp.listStageArtifacts(id, stageId, options).then((request) => request(axios, basePath));
},
/**
* Returns a paginated list of conversation turns within a specific stage, including system prompts, assistant responses, and tool invocations.
* @summary List Stage Turns
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph.
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {*} [options] Override http request option.
@ -324,6 +961,30 @@ export const RunInternalsApiFactory = function (configuration?: Configuration, b
listStageTurns(id: string, stageId: string, pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedStageTurnList> {
return localVarFp.listStageTurns(id, stageId, pageLimit, pageOffset, options).then((request) => request(axios, basePath));
},
/**
* Uploads an artifact for a stage. Intended for trusted internal callers.
* @summary Put Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
putStageArtifact(id: string, stageId: string, filename: string, body: File, options?: RawAxiosRequestConfig): AxiosPromise<void> {
return localVarFp.putStageArtifact(id, stageId, filename, body, options).then((request) => request(axios, basePath));
},
/**
* Reads a previously stored blob by identifier.
* @summary Read Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {string} blobId Content-addressed blob identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
readRunBlob(id: string, blobId: string, options?: RawAxiosRequestConfig): AxiosPromise<File> {
return localVarFp.readRunBlob(id, blobId, options).then((request) => request(axios, basePath));
},
/**
* Returns the latest checkpoint data for a run, or null if no checkpoint has been recorded yet.
* @summary Retrieve Run Checkpoint
@ -344,6 +1005,17 @@ export const RunInternalsApiFactory = function (configuration?: Configuration, b
retrieveRunSettings(id: string, options?: RawAxiosRequestConfig): AxiosPromise<RunSettings> {
return localVarFp.retrieveRunSettings(id, options).then((request) => request(axios, basePath));
},
/**
* Writes an opaque binary blob and returns its content-addressed blob identifier.
* @summary Write Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
writeRunBlob(id: string, body: File, options?: RawAxiosRequestConfig): AxiosPromise<WriteBlobResponse> {
return localVarFp.writeRunBlob(id, body, options).then((request) => request(axios, basePath));
},
};
};
@ -351,6 +1023,67 @@ export const RunInternalsApiFactory = function (configuration?: Configuration, b
* RunInternalsApi - object-oriented interface
*/
export class RunInternalsApi extends BaseAPI {
/**
* Appends a validated event to the run event log. Intended for trusted internal callers.
* @summary Append Run Event
* @param {string} id Unique run identifier (ULID).
* @param {RunEvent} runEvent
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public appendRunEvent(id: string, runEvent: RunEvent, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).appendRunEvent(id, runEvent, options).then((request) => request(this.axios, this.basePath));
}
/**
* Opens a server-sent event stream for a live run. Optionally replays stored events from `since_seq` before switching to live updates.
* @summary Attach Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public attachRunEvents(id: string, sinceSeq?: number, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).attachRunEvents(id, sinceSeq, options).then((request) => request(this.axios, this.basePath));
}
/**
* Returns the internal event-sourced run projection. This is not a stable public contract.
* @summary Get Run State
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public getRunState(id: string, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).getRunState(id, options).then((request) => request(this.axios, this.basePath));
}
/**
* Downloads an artifact by filename.
* @summary Get Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public getStageArtifact(id: string, stageId: string, filename: string, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).getStageArtifact(id, stageId, filename, options).then((request) => request(this.axios, this.basePath));
}
/**
* Returns a paginated JSON list of stored run events.
* @summary List Run Events
* @param {string} id Unique run identifier (ULID).
* @param {number} [sinceSeq] First event sequence number to include.
* @param {number} [limit] Maximum number of events to return.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public listRunEvents(id: string, sinceSeq?: number, limit?: number, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).listRunEvents(id, sinceSeq, limit, options).then((request) => request(this.axios, this.basePath));
}
/**
* Returns the ordered list of stages in a run\'s workflow graph with their current status and timing. Stages are bounded by the workflow graph size, typically fewer than 20.
* @summary List Run Stages
@ -364,11 +1097,23 @@ export class RunInternalsApi extends BaseAPI {
return RunInternalsApiFp(this.configuration).listRunStages(id, pageLimit, pageOffset, options).then((request) => request(this.axios, this.basePath));
}
/**
* Lists artifact filenames stored for a stage.
* @summary List Stage Artifacts
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public listStageArtifacts(id: string, stageId: string, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).listStageArtifacts(id, stageId, options).then((request) => request(this.axios, this.basePath));
}
/**
* Returns a paginated list of conversation turns within a specific stage, including system prompts, assistant responses, and tool invocations.
* @summary List Stage Turns
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph.
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {*} [options] Override http request option.
@ -378,6 +1123,32 @@ export class RunInternalsApi extends BaseAPI {
return RunInternalsApiFp(this.configuration).listStageTurns(id, stageId, pageLimit, pageOffset, options).then((request) => request(this.axios, this.basePath));
}
/**
* Uploads an artifact for a stage. Intended for trusted internal callers.
* @summary Put Stage Artifact
* @param {string} id Unique run identifier (ULID).
* @param {string} stageId Identifier of a stage within a run\&#39;s workflow graph, serialized as &#x60;node_id@visit&#x60;.
* @param {string} filename Artifact filename. May contain path separators.
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public putStageArtifact(id: string, stageId: string, filename: string, body: File, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).putStageArtifact(id, stageId, filename, body, options).then((request) => request(this.axios, this.basePath));
}
/**
* Reads a previously stored blob by identifier.
* @summary Read Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {string} blobId Content-addressed blob identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public readRunBlob(id: string, blobId: string, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).readRunBlob(id, blobId, options).then((request) => request(this.axios, this.basePath));
}
/**
* Returns the latest checkpoint data for a run, or null if no checkpoint has been recorded yet.
* @summary Retrieve Run Checkpoint
@ -399,5 +1170,17 @@ export class RunInternalsApi extends BaseAPI {
public retrieveRunSettings(id: string, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).retrieveRunSettings(id, options).then((request) => request(this.axios, this.basePath));
}
/**
* Writes an opaque binary blob and returns its content-addressed blob identifier.
* @summary Write Run Blob
* @param {string} id Unique run identifier (ULID).
* @param {File} body
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public writeRunBlob(id: string, body: File, options?: RawAxiosRequestConfig) {
return RunInternalsApiFp(this.configuration).writeRunBlob(id, body, options).then((request) => request(this.axios, this.basePath));
}
}

View file

@ -328,47 +328,6 @@ export const RunsApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
/**
* Opens a server-sent event (SSE) stream for real-time run updates. Returns 410 if the stream has been closed.
* @summary Stream Run Events
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
streamRunEvents: async (id: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('streamRunEvents', 'id', id)
const localVarPath = `/api/v1/runs/{id}/events`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication mTLS required
await setApiKeyToObject(localVarHeaderParameter, "X-mTLS-Client-CN", configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Accept'] = 'text/event-stream,application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Resumes a paused run. Returns 409 if the run is not paused.
* @summary Unpause Run
@ -511,19 +470,6 @@ export const RunsApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['RunsApi.startRun']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Opens a server-sent event (SSE) stream for real-time run updates. Returns 410 if the stream has been closed.
* @summary Stream Run Events
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async streamRunEvents(id: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<string>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.streamRunEvents(id, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunsApi.streamRunEvents']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Resumes a paused run. Returns 409 if the run is not paused.
* @summary Unpause Run
@ -617,16 +563,6 @@ export const RunsApiFactory = function (configuration?: Configuration, basePath?
startRun(id: string, options?: RawAxiosRequestConfig): AxiosPromise<RunStatusResponse> {
return localVarFp.startRun(id, options).then((request) => request(axios, basePath));
},
/**
* Opens a server-sent event (SSE) stream for real-time run updates. Returns 410 if the stream has been closed.
* @summary Stream Run Events
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
streamRunEvents(id: string, options?: RawAxiosRequestConfig): AxiosPromise<string> {
return localVarFp.streamRunEvents(id, options).then((request) => request(axios, basePath));
},
/**
* Resumes a paused run. Returns 409 if the run is not paused.
* @summary Unpause Run
@ -722,17 +658,6 @@ export class RunsApi extends BaseAPI {
return RunsApiFp(this.configuration).startRun(id, options).then((request) => request(this.axios, this.basePath));
}
/**
* Opens a server-sent event (SSE) stream for real-time run updates. Returns 410 if the stream has been closed.
* @summary Stream Run Events
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public streamRunEvents(id: string, options?: RawAxiosRequestConfig) {
return RunsApiFp(this.configuration).streamRunEvents(id, options).then((request) => request(this.axios, this.basePath));
}
/**
* Resumes a paused run. Returns 409 if the run is not paused.
* @summary Unpause Run

View file

@ -0,0 +1,26 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* Assigned sequence number for an appended event.
*/
export interface AppendEventResponse {
/**
* Assigned event sequence number.
*/
'seq': number;
}

View file

@ -0,0 +1,26 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* A single artifact filename.
*/
export interface ArtifactEntry {
/**
* Artifact filename.
*/
'filename': string;
}

View file

@ -0,0 +1,26 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { ArtifactEntry } from './artifact-entry';
/**
* List of artifact filenames for a stage.
*/
export interface ArtifactListResponse {
'data': Array<ArtifactEntry>;
}

View file

@ -0,0 +1,30 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { RunEvent } from './run-event';
/**
* Stored event envelope with assigned sequence number.
*/
export interface EventEnvelope {
/**
* Assigned event sequence number.
*/
'seq': number;
'payload': RunEvent;
}

View file

@ -3,6 +3,9 @@ export * from './aggregate-usage-totals';
export * from './api-question';
export * from './api-question-option';
export * from './api-settings';
export * from './append-event-response';
export * from './artifact-entry';
export * from './artifact-list-response';
export * from './artifacts-settings';
export * from './assistant-stage-turn';
export * from './assistant-turn';
@ -36,6 +39,7 @@ export * from './diff-file';
export * from './diff-stats';
export * from './error-response';
export * from './error-response-entry';
export * from './event-envelope';
export * from './execute-query-request';
export * from './execute-query-response';
export * from './execute-query-response-rows-inner-inner';
@ -50,6 +54,8 @@ export * from './git-settings';
export * from './health-response';
export * from './history-entry';
export * from './hook-definition';
export * from './internal-run-status';
export * from './internal-stage-status';
export * from './learning';
export * from './learning-category';
export * from './llm-settings';
@ -62,9 +68,12 @@ export * from './model-features';
export * from './model-limits';
export * from './model-reference';
export * from './model-test-result';
export * from './node-state';
export * from './node-status-record';
export * from './open-item';
export * from './open-item-kind';
export * from './paginated-api-question-list';
export * from './paginated-event-list';
export * from './paginated-history-entry-list';
export * from './paginated-model-list';
export * from './paginated-retro-list';
@ -93,7 +102,10 @@ export * from './root-response';
export * from './root-response-urls';
export * from './run-checkpoint';
export * from './run-error';
export * from './run-event';
export * from './run-list-item';
export * from './run-projection';
export * from './run-projection-checkpoints-inner-inner';
export * from './run-pull-request';
export * from './run-question';
export * from './run-reference';
@ -101,6 +113,7 @@ export * from './run-sandbox';
export * from './run-settings';
export * from './run-stage';
export * from './run-status';
export * from './run-status-record';
export * from './run-status-response';
export * from './run-timings';
export * from './run-usage';
@ -124,6 +137,7 @@ export * from './smoothness-rating';
export * from './stage-retro';
export * from './stage-status';
export * from './stage-turn';
export * from './status-reason';
export * from './steer-request';
export * from './submit-answer-request';
export * from './system-stage-turn';
@ -153,3 +167,4 @@ export * from './workflow-last-run';
export * from './workflow-list-item';
export * from './workflow-reference';
export * from './workflow-schedule';
export * from './write-blob-response';

View file

@ -0,0 +1,35 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* Internal event-sourced run status.
*/
export const InternalRunStatus = {
SUBMITTED: 'submitted',
STARTING: 'starting',
RUNNING: 'running',
PAUSED: 'paused',
REMOVING: 'removing',
SUCCEEDED: 'succeeded',
FAILED: 'failed',
DEAD: 'dead'
} as const;
export type InternalRunStatus = typeof InternalRunStatus[keyof typeof InternalRunStatus];

View file

@ -0,0 +1,32 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* Internal stage status from outcomes and node status records.
*/
export const InternalStageStatus = {
SUCCESS: 'success',
FAIL: 'fail',
SKIPPED: 'skipped',
PARTIAL_SUCCESS: 'partial_success',
RETRY: 'retry'
} as const;
export type InternalStageStatus = typeof InternalStageStatus[keyof typeof InternalStageStatus];

View file

@ -0,0 +1,35 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { NodeStatusRecord } from './node-status-record';
/**
* Internal node projection state.
*/
export interface NodeState {
'prompt'?: string;
'response'?: string;
'status'?: NodeStatusRecord | null;
'provider_used'?: any;
'diff'?: string;
'script_invocation'?: any;
'script_timing'?: any;
'parallel_results'?: any;
'stdout'?: string;
'stderr'?: string;
}

View file

@ -0,0 +1,31 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { InternalStageStatus } from './internal-stage-status';
/**
* Internal node status record.
*/
export interface NodeStatusRecord {
'status': InternalStageStatus;
'notes'?: string;
'failure_reason'?: string;
'timestamp': string;
}

View file

@ -0,0 +1,30 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { EventEnvelope } from './event-envelope';
// May contain unused imports in some cases
// @ts-ignore
import type { PaginationMeta } from './pagination-meta';
/**
* Paginated list of stored run events.
*/
export interface PaginatedEventList {
'data': Array<EventEnvelope>;
'meta': PaginationMeta;
}

View file

@ -0,0 +1,36 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* Internal RunEvent-compatible JSON payload. The server validates this body by deserializing into the typed RunEvent struct.
*/
export interface RunEvent {
[key: string]: any;
'id': string;
'ts': string;
'run_id': string;
'node_id'?: string;
'node_label'?: string;
'session_id'?: string;
'parent_session_id'?: string;
/**
* Event type discriminator.
*/
'event': string;
'properties'?: { [key: string]: any; };
}

View file

@ -0,0 +1,25 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { RunCheckpoint } from './run-checkpoint';
/**
* @type RunProjectionCheckpointsInnerInner
*/
export type RunProjectionCheckpointsInnerInner = RunCheckpoint | number;

View file

@ -0,0 +1,54 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { NodeState } from './node-state';
// May contain unused imports in some cases
// @ts-ignore
import type { RunCheckpoint } from './run-checkpoint';
// May contain unused imports in some cases
// @ts-ignore
import type { RunProjectionCheckpointsInnerInner } from './run-projection-checkpoints-inner-inner';
// May contain unused imports in some cases
// @ts-ignore
import type { RunStatusRecord } from './run-status-record';
/**
* Raw internal run projection derived from the event log.
*/
export interface RunProjection {
'run'?: { [key: string]: any; };
'graph_source'?: string;
'start'?: { [key: string]: any; };
'status'?: RunStatusRecord | null;
'checkpoint'?: RunCheckpoint | null;
/**
* Sequence-tagged checkpoint history entries as `[seq, checkpoint]`.
*/
'checkpoints'?: Array<Array<RunProjectionCheckpointsInnerInner>>;
'conclusion'?: { [key: string]: any; };
'retro'?: { [key: string]: any; };
'retro_prompt'?: string;
'retro_response'?: string;
'sandbox'?: { [key: string]: any; };
'final_patch'?: string;
'pull_request'?: { [key: string]: any; };
/**
* Map from StageId (`node_id@visit`) to NodeState.
*/
'nodes': { [key: string]: NodeState; };
}

View file

@ -0,0 +1,33 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// May contain unused imports in some cases
// @ts-ignore
import type { InternalRunStatus } from './internal-run-status';
// May contain unused imports in some cases
// @ts-ignore
import type { StatusReason } from './status-reason';
/**
* Internal run status record from the event projection.
*/
export interface RunStatusRecord {
'status': InternalRunStatus;
'reason'?: StatusReason | null;
'updated_at': string;
}

View file

@ -0,0 +1,38 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* Optional reason attached to a run status transition.
*/
export const StatusReason = {
COMPLETED: 'completed',
PARTIAL_SUCCESS: 'partial_success',
WORKFLOW_ERROR: 'workflow_error',
CANCELLED: 'cancelled',
TERMINATED: 'terminated',
TRANSIENT_INFRA: 'transient_infra',
BUDGET_EXHAUSTED: 'budget_exhausted',
LAUNCH_FAILED: 'launch_failed',
BOOTSTRAP_FAILED: 'bootstrap_failed',
SANDBOX_INIT_FAILED: 'sandbox_init_failed',
SANDBOX_INITIALIZING: 'sandbox_initializing'
} as const;
export type StatusReason = typeof StatusReason[keyof typeof StatusReason];

View file

@ -0,0 +1,26 @@
/* tslint:disable */
/* eslint-disable */
/**
* Fabro Run API
* HTTP API for managing Fabro workflow run executions.
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/**
* Content-addressed identifier for a stored blob.
*/
export interface WriteBlobResponse {
/**
* Blob identifier.
*/
'id': string;
}