feat: show archived runs on the runs page

Extend GET /api/v1/boards/runs with include_archived=true (matching the
existing flag on listRuns), add an Archived BoardColumn that the server
appends only when the flag is set, and surface a "Show archived" toggle
on /runs that flips between request shapes. Default behavior is unchanged
— archived runs stay hidden.

Server: list_board_runs now takes ListRunsParams; board_column maps
RunStatus::Archived to BoardColumn::Archived; board_columns(include_archived)
appends the column conditionally. Two new handler tests cover the default
and flag-on paths.

Web: useBoardsRuns(includeArchived) keys requests so SWR refetches on
toggle; columnStatuses + columnStatusDisplay + columnStyles get an
"archived" entry; buildSkeletonColumns filters by the flag so the loading
state matches the eventual response. Two new buildBoardColumns tests cover
both column shapes.

Touched generated TS client files include unrelated whitespace drift from
openapi-generator-cli; including them keeps the working tree consistent
with what `bun run generate` produces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-05-07 08:36:04 -07:00
parent 9b10f7d4fb
commit c8336a250e
No known key found for this signature in database
15 changed files with 296 additions and 52 deletions

View file

@ -48,6 +48,7 @@ export const columnStatuses = [
BoardColumn.BLOCKED,
BoardColumn.SUCCEEDED,
BoardColumn.FAILED,
BoardColumn.ARCHIVED,
] as const satisfies readonly ColumnStatus[];
export const columnStatusDisplay: Record<ColumnStatus, { label: string; dot: string; text: string }> = {
@ -57,6 +58,7 @@ export const columnStatusDisplay: Record<ColumnStatus, { label: string; dot: str
blocked: { label: "Blocked", dot: "bg-amber", text: "text-amber" },
succeeded: { label: "Succeeded", dot: "bg-teal-300", text: "text-teal-300" },
failed: { label: "Failed", dot: "bg-coral", text: "text-coral" },
archived: { label: "Archived", dot: "bg-fg-muted", text: "text-fg-muted" },
};
export interface RunWithStatus extends RunItem {

View file

@ -63,8 +63,11 @@ export function useSystemInfo() {
);
}
export function useBoardsRuns() {
return useSWR<BoardRunsEnvelope>(queryKeys.boards.runs(), apiPaginatedFetcher);
export function useBoardsRuns(includeArchived: boolean = false) {
return useSWR<BoardRunsEnvelope>(
queryKeys.boards.runs(includeArchived),
apiPaginatedFetcher,
);
}
export function useRun(id: string | undefined) {

View file

@ -24,7 +24,10 @@ export const queryKeys = {
attach: () => "/api/v1/attach",
},
boards: {
runs: () => "/api/v1/boards/runs",
runs: (includeArchived = false) =>
withQuery("/api/v1/boards/runs", {
include_archived: includeArchived ? "true" : null,
}),
},
runs: {
detail: (id: string) => `/api/v1/runs/${pathSegment(id)}`,

View file

@ -44,6 +44,58 @@ describe("runs route board mapping", () => {
expect(columns.find((column) => column.id === "blocked")?.items[0]?.question).toBe("Older unresolved question?");
});
test("renders an archived column when the response includes one", () => {
const columns = buildBoardColumns({
columns: [
{ id: "queued", name: "Queued" },
{ id: "initializing", name: "Initializing" },
{ id: "running", name: "Running" },
{ id: "blocked", name: "Blocked" },
{ id: "succeeded", name: "Succeeded" },
{ id: "failed", name: "Failed" },
{ id: "archived", name: "Archived" },
],
data: [
boardRun("succeeded-run", "succeeded"),
boardRun("archived-run", "archived"),
],
meta: { has_more: false },
});
expect(columns.map((column) => column.id)).toEqual([
"queued",
"initializing",
"running",
"blocked",
"succeeded",
"failed",
"archived",
]);
expect(
columns.find((column) => column.id === "archived")?.items.map((item) => item.id),
).toEqual(["archived-run"]);
expect(
columns.find((column) => column.id === "succeeded")?.items.map((item) => item.id),
).toEqual(["succeeded-run"]);
});
test("omits the archived column when the response does not include it", () => {
const columns = buildBoardColumns({
columns: [
{ id: "queued", name: "Queued" },
{ id: "initializing", name: "Initializing" },
{ id: "running", name: "Running" },
{ id: "blocked", name: "Blocked" },
{ id: "succeeded", name: "Succeeded" },
{ id: "failed", name: "Failed" },
],
data: [boardRun("succeeded-run", "succeeded")],
meta: { has_more: false },
});
expect(columns.some((column) => column.id === "archived")).toBe(false);
});
test("refreshes for blocked status and interview events", () => {
expect(shouldRefreshBoardForEvent("run.queued")).toBe(true);
expect(shouldRefreshBoardForEvent("run.blocked")).toBe(true);

View file

@ -1,6 +1,6 @@
import { useState, useCallback, useEffect, useMemo, useRef } from "react";
import { Link } from "react-router";
import { ChevronDownIcon, CommandLineIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { ArchiveBoxIcon, ChevronDownIcon, CommandLineIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
import { useSWRConfig } from "swr";
@ -50,6 +50,7 @@ const columnStyles: Record<ColumnStatus, ColumnStyle> = {
blocked: { iconType: "branch", actions: ["Answer Question"] },
succeeded: { iconType: "pr", actions: [] },
failed: { iconType: "branch", actions: [] },
archived: { iconType: "branch", actions: [] },
};
const defaultColumnStyle: ColumnStyle = { iconType: "branch", actions: [] };
@ -71,18 +72,20 @@ type Column = {
items: RunItem[];
};
function buildSkeletonColumns(): Column[] {
return columnStatuses.map((id) => {
const colors = columnStatusDisplay[id];
return {
id,
name: colors.label,
dot: colors.dot,
text: colors.text,
...(columnStyles[id] ?? defaultColumnStyle),
items: [],
};
});
function buildSkeletonColumns(includeArchived: boolean): Column[] {
return columnStatuses
.filter((id) => includeArchived || id !== "archived")
.map((id) => {
const colors = columnStatusDisplay[id];
return {
id,
name: colors.label,
dot: colors.dot,
text: colors.text,
...(columnStyles[id] ?? defaultColumnStyle),
items: [],
};
});
}
export function buildBoardColumns(response: BoardRunsResponse): Column[] {
@ -750,7 +753,8 @@ function RunsLandingEmpty({
}
export default function Runs() {
const boardRuns = useBoardsRuns();
const [includeArchived, setIncludeArchived] = useState(false);
const boardRuns = useBoardsRuns(includeArchived);
const authConfig = useAuthConfig();
const systemInfo = useSystemInfo();
const isLandingReady =
@ -758,8 +762,11 @@ export default function Runs() {
authConfig.data !== undefined &&
systemInfo.data !== undefined;
const initialColumns = useMemo(
() => boardRuns.data ? buildBoardColumns(boardRuns.data) : buildSkeletonColumns(),
[boardRuns.data],
() =>
boardRuns.data
? buildBoardColumns(boardRuns.data)
: buildSkeletonColumns(includeArchived),
[boardRuns.data, includeArchived],
);
const hasGitHubAuth = authConfig.data?.methods.includes("github") === true;
const serverUrl = systemInfo.data?.server_url;
@ -851,6 +858,16 @@ export default function Runs() {
</select>
<ChevronDownIcon className="pointer-events-none absolute right-2 top-1/2 size-4 -translate-y-1/2 text-fg-muted" />
</div>
<button
type="button"
onClick={() => setIncludeArchived((v) => !v)}
aria-pressed={includeArchived}
title={includeArchived ? "Hide archived runs" : "Show archived runs"}
className={`inline-flex items-center gap-1.5 rounded-md border border-line bg-panel/80 px-3 py-2 text-xs font-medium transition-colors ${includeArchived ? "text-teal-500" : "text-fg-muted hover:text-fg-3"}`}
>
<ArchiveBoxIcon className="size-4" aria-hidden="true" />
<span>Show archived</span>
</button>
<div role="group" aria-label="Run list view" className="flex rounded-md border border-line bg-panel/80 p-0.5">
<button
type="button"

View file

@ -1417,10 +1417,11 @@ paths:
operationId: listBoardRuns
tags: [Runs]
summary: List Board Runs
description: Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves.
description: Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves. Archived runs are hidden by default; pass `include_archived=true` to include them under the `archived` column.
parameters:
- $ref: "#/components/parameters/PageLimit"
- $ref: "#/components/parameters/PageOffset"
- $ref: "#/components/parameters/IncludeArchived"
responses:
"200":
description: Paginated list of runs for the board view
@ -5805,6 +5806,7 @@ components:
- blocked
- succeeded
- failed
- archived
BoardColumnDefinition:
type: object

View file

@ -92,12 +92,13 @@ fn board_column(status: RunStatus) -> Option<BoardColumn> {
RunStatus::Blocked { .. } => Some(BoardColumn::Blocked),
RunStatus::Succeeded { .. } => Some(BoardColumn::Succeeded),
RunStatus::Failed { .. } | RunStatus::Dead => Some(BoardColumn::Failed),
RunStatus::Removing | RunStatus::Archived { .. } => None,
RunStatus::Archived { .. } => Some(BoardColumn::Archived),
RunStatus::Removing => None,
}
}
pub(crate) fn board_columns() -> Vec<BoardColumnDefinition> {
vec![
pub(crate) fn board_columns(include_archived: bool) -> Vec<BoardColumnDefinition> {
let mut columns = vec![
BoardColumnDefinition {
id: BoardColumn::Queued,
name: "Queued".into(),
@ -122,7 +123,14 @@ pub(crate) fn board_columns() -> Vec<BoardColumnDefinition> {
id: BoardColumn::Failed,
name: "Failed".into(),
},
]
];
if include_archived {
columns.push(BoardColumnDefinition {
id: BoardColumn::Archived,
name: "Archived".into(),
});
}
columns
}
fn board_run_metadata_from_projection(
@ -187,7 +195,7 @@ fn paginate_items<T>(items: Vec<T>, pagination: &PaginationParams) -> (Vec<T>, b
async fn list_board_runs(
_auth: RequiredUser,
State(state): State<Arc<AppState>>,
Query(pagination): Query<PaginationParams>,
Query(params): Query<ListRunsParams>,
) -> Response {
let entries = match state
.store
@ -200,14 +208,18 @@ async fn list_board_runs(
.into_response();
}
};
let include_archived = params.include_archived;
let board_summaries: Vec<_> = entries
.into_iter()
.filter_map(|entry| {
let column = board_column(entry.summary.status)?;
if column == BoardColumn::Archived && !include_archived {
return None;
}
Some((entry, column))
})
.collect();
let (page_summaries, has_more) = paginate_items(board_summaries, &pagination);
let (page_summaries, has_more) = paginate_items(board_summaries, &params.pagination());
let mut data = Vec::with_capacity(page_summaries.len());
for (entry, column) in page_summaries {
@ -222,7 +234,7 @@ async fn list_board_runs(
(
StatusCode::OK,
Json(serde_json::json!({
"columns": board_columns(),
"columns": board_columns(include_archived),
"data": data,
"meta": { "has_more": has_more }
})),

View file

@ -8282,6 +8282,139 @@ async fn boards_runs_excludes_removing_status() {
assert!(!found, "removing run should not appear on the board");
}
#[tokio::test]
async fn boards_runs_excludes_archived_by_default() {
let state = test_app_state();
let app = crate::test_support::build_test_router(Arc::clone(&state));
let run_id = fixtures::RUN_1;
create_durable_run_with_events(&state, run_id, &[
workflow_event::Event::RunSubmitted {
definition_blob: None,
},
workflow_event::Event::RunStarting,
workflow_event::Event::RunRunning,
workflow_event::Event::WorkflowRunCompleted {
duration_ms: 1000,
artifact_count: 0,
status: "succeeded".to_string(),
reason: SuccessReason::Completed,
total_usd_micros: None,
final_git_commit_sha: None,
final_patch: None,
billing: None,
},
workflow_event::Event::RunArchived { actor: None },
])
.await;
let req = Request::builder()
.method("GET")
.uri(api("/boards/runs"))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
let body = response_json!(response, StatusCode::OK).await;
let data = body["data"].as_array().expect("data should be array");
assert!(
!data
.iter()
.any(|i| i["run_id"].as_str() == Some(&run_id.to_string())),
"archived run should be hidden when include_archived is unset",
);
let columns = body["columns"].as_array().expect("columns should be array");
assert!(
!columns.iter().any(|c| c["id"].as_str() == Some("archived")),
"archived column should not appear in default response",
);
}
#[tokio::test]
async fn boards_runs_includes_archived_when_flag_set() {
let state = test_app_state();
let app = crate::test_support::build_test_router(Arc::clone(&state));
let archived_id = fixtures::RUN_1;
let succeeded_id = fixtures::RUN_2;
create_durable_run_with_events(&state, archived_id, &[
workflow_event::Event::RunSubmitted {
definition_blob: None,
},
workflow_event::Event::RunStarting,
workflow_event::Event::RunRunning,
workflow_event::Event::WorkflowRunCompleted {
duration_ms: 1000,
artifact_count: 0,
status: "succeeded".to_string(),
reason: SuccessReason::Completed,
total_usd_micros: None,
final_git_commit_sha: None,
final_patch: None,
billing: None,
},
workflow_event::Event::RunArchived { actor: None },
])
.await;
create_durable_run_with_events(&state, succeeded_id, &[
workflow_event::Event::RunSubmitted {
definition_blob: None,
},
workflow_event::Event::RunStarting,
workflow_event::Event::RunRunning,
workflow_event::Event::WorkflowRunCompleted {
duration_ms: 1000,
artifact_count: 0,
status: "succeeded".to_string(),
reason: SuccessReason::Completed,
total_usd_micros: None,
final_git_commit_sha: None,
final_patch: None,
billing: None,
},
])
.await;
let req = Request::builder()
.method("GET")
.uri(api("/boards/runs?include_archived=true"))
.body(Body::empty())
.unwrap();
let response = app.oneshot(req).await.unwrap();
let body = response_json!(response, StatusCode::OK).await;
let data = body["data"].as_array().expect("data should be array");
let archived_item = data
.iter()
.find(|i| i["run_id"].as_str() == Some(&archived_id.to_string()))
.expect("archived run should appear when include_archived=true");
assert_eq!(archived_item["column"].as_str().unwrap(), "archived");
assert_eq!(archived_item["status"]["kind"].as_str().unwrap(), "archived");
let succeeded_item = data
.iter()
.find(|i| i["run_id"].as_str() == Some(&succeeded_id.to_string()))
.expect("non-archived run should still appear");
assert_eq!(succeeded_item["column"].as_str().unwrap(), "succeeded");
let columns = body["columns"].as_array().expect("columns should be array");
let column_ids: Vec<_> = columns
.iter()
.map(|c| c["id"].as_str().unwrap().to_string())
.collect();
assert_eq!(
column_ids,
vec![
"queued",
"initializing",
"running",
"blocked",
"succeeded",
"failed",
"archived",
],
);
}
#[tokio::test]
async fn get_run_exposes_canonical_operator_statuses() {
let state = test_app_state();

View file

@ -182,7 +182,7 @@ export const HumanInTheLoopApiAxiosParamCreator = function (configuration?: Conf
};
},
/**
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* @summary Interrupt Run
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
@ -376,10 +376,10 @@ export const HumanInTheLoopApiAxiosParamCreator = function (configuration?: Conf
};
},
/**
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* @summary Steer Run
* @param {string} id Unique run identifier (ULID).
* @param {SteerRunRequest} steerRunRequest
* @param {SteerRunRequest} steerRunRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -521,7 +521,7 @@ export const HumanInTheLoopApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* @summary Interrupt Run
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
@ -579,10 +579,10 @@ export const HumanInTheLoopApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* @summary Steer Run
* @param {string} id Unique run identifier (ULID).
* @param {SteerRunRequest} steerRunRequest
* @param {SteerRunRequest} steerRunRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -650,7 +650,7 @@ export const HumanInTheLoopApiFactory = function (configuration?: Configuration,
return localVarFp.getSandboxFile(id, path, options).then((request) => request(axios, basePath));
},
/**
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* @summary Interrupt Run
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
@ -696,10 +696,10 @@ export const HumanInTheLoopApiFactory = function (configuration?: Configuration,
return localVarFp.putSandboxFile(id, path, body, options).then((request) => request(axios, basePath));
},
/**
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* @summary Steer Run
* @param {string} id Unique run identifier (ULID).
* @param {SteerRunRequest} steerRunRequest
* @param {SteerRunRequest} steerRunRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -762,7 +762,7 @@ export class HumanInTheLoopApi extends BaseAPI {
}
/**
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* Interrupt the active API-mode agent round without sending steering text. The agent keeps its steering lease and waits for a later steer message before starting another LLM round.
* @summary Interrupt Run
* @param {string} id Unique run identifier (ULID).
* @param {*} [options] Override http request option.
@ -812,10 +812,10 @@ export class HumanInTheLoopApi extends BaseAPI {
}
/**
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* Send a mid-run steering message to the live agent session(s) of a running run. Set `interrupt=true` to atomically interrupt the active API-mode agent round first, then deliver this message as the next user turn. Without `interrupt=true`, the message is appended to the steering queue and may buffer until the next API-mode agent session.
* @summary Steer Run
* @param {string} id Unique run identifier (ULID).
* @param {SteerRunRequest} steerRunRequest
* @param {SteerRunRequest} steerRunRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -836,3 +836,4 @@ export class HumanInTheLoopApi extends BaseAPI {
return HumanInTheLoopApiFp(this.configuration).submitRunAnswer(id, qid, submitAnswerRequest, options).then((request) => request(this.axios, this.basePath));
}
}

View file

@ -443,14 +443,15 @@ export const RunsApiAxiosParamCreator = function (configuration?: Configuration)
};
},
/**
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves.
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves. Archived runs are hidden by default; pass `include_archived=true` to include them under the `archived` column.
* @summary List Board Runs
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {boolean} [includeArchived] Whether to include archived runs in the response. Defaults to &#x60;false&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listBoardRuns: async (pageLimit?: number, pageOffset?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
listBoardRuns: async (pageLimit?: number, pageOffset?: number, includeArchived?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/v1/boards/runs`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
@ -477,6 +478,10 @@ export const RunsApiAxiosParamCreator = function (configuration?: Configuration)
localVarQueryParameter['page[offset]'] = pageOffset;
}
if (includeArchived !== undefined) {
localVarQueryParameter['include_archived'] = includeArchived;
}
localVarHeaderParameter['Accept'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
@ -1206,15 +1211,16 @@ export const RunsApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves.
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves. Archived runs are hidden by default; pass `include_archived=true` to include them under the `archived` column.
* @summary List Board Runs
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {boolean} [includeArchived] Whether to include archived runs in the response. Defaults to &#x60;false&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listBoardRuns(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PaginatedBoardRunList>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listBoardRuns(pageLimit, pageOffset, options);
async listBoardRuns(pageLimit?: number, pageOffset?: number, includeArchived?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PaginatedBoardRunList>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listBoardRuns(pageLimit, pageOffset, includeArchived, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['RunsApi.listBoardRuns']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
@ -1509,15 +1515,16 @@ export const RunsApiFactory = function (configuration?: Configuration, basePath?
return localVarFp.getRunTimeline(id, options).then((request) => request(axios, basePath));
},
/**
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves.
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves. Archived runs are hidden by default; pass `include_archived=true` to include them under the `archived` column.
* @summary List Board Runs
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {boolean} [includeArchived] Whether to include archived runs in the response. Defaults to &#x60;false&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listBoardRuns(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedBoardRunList> {
return localVarFp.listBoardRuns(pageLimit, pageOffset, options).then((request) => request(axios, basePath));
listBoardRuns(pageLimit?: number, pageOffset?: number, includeArchived?: boolean, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedBoardRunList> {
return localVarFp.listBoardRuns(pageLimit, pageOffset, includeArchived, options).then((request) => request(axios, basePath));
},
/**
* Returns durable run summaries from the backing store, including runs persisted before the current server boot. Archived runs are hidden by default; pass `include_archived=true` to include them in the response.
@ -1774,15 +1781,16 @@ export class RunsApi extends BaseAPI {
}
/**
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves.
* Temporary board-view list of managed runs. This endpoint is UI-oriented and may change as the app evolves. Archived runs are hidden by default; pass `include_archived=true` to include them under the `archived` column.
* @summary List Board Runs
* @param {number} [pageLimit] Maximum number of items to return per page.
* @param {number} [pageOffset] Number of items to skip before returning results.
* @param {boolean} [includeArchived] Whether to include archived runs in the response. Defaults to &#x60;false&#x60;.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public listBoardRuns(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig) {
return RunsApiFp(this.configuration).listBoardRuns(pageLimit, pageOffset, options).then((request) => request(this.axios, this.basePath));
public listBoardRuns(pageLimit?: number, pageOffset?: number, includeArchived?: boolean, options?: RawAxiosRequestConfig) {
return RunsApiFp(this.configuration).listBoardRuns(pageLimit, pageOffset, includeArchived, options).then((request) => request(this.axios, this.basePath));
}
/**

View file

@ -21,3 +21,6 @@ export interface BoardColumnDefinition {
'id': BoardColumn;
'name': string;
}

View file

@ -24,7 +24,8 @@ export const BoardColumn = {
RUNNING: 'running',
BLOCKED: 'blocked',
SUCCEEDED: 'succeeded',
FAILED: 'failed'
FAILED: 'failed',
ARCHIVED: 'archived'
} as const;
export type BoardColumn = typeof BoardColumn[keyof typeof BoardColumn];

View file

@ -43,3 +43,6 @@ export interface RunBillingStage {
'started_at'?: string | null;
'state'?: StageState | null;
}

View file

@ -65,3 +65,6 @@ export interface StageProjection {
'duration_ms'?: number | null;
'state'?: StageState | null;
}

View file

@ -23,7 +23,8 @@ export interface SteerRunRequest {
*/
'text': string;
/**
* When true, apply a worker-control interrupt first, then deliver this text as steering in the same control operation. When false (default), append to the steering queue and let the agent pick it up at the next turn boundary.
* When true, apply a worker-control interrupt first, then deliver this text as steering in the same control operation. When false (default), append to the steering queue and let the agent pick it up at the next turn boundary.
*/
'interrupt'?: boolean;
}