1429 lines
58 KiB
YAML
1429 lines
58 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: byre
|
|
version: 0.0.0
|
|
paths:
|
|
/api/me:
|
|
get:
|
|
operationId: getMe
|
|
responses:
|
|
"200":
|
|
description: The calling user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
put:
|
|
operationId: updateMe
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/UserUpdate" }
|
|
responses:
|
|
"200":
|
|
description: The updated user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/notifications:
|
|
put:
|
|
operationId: updateNotificationPrefs
|
|
description: Sets which new inbox items notify the calling user in their open byre pages.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/NotificationPrefs" }
|
|
responses:
|
|
"200":
|
|
description: The updated user.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/User" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/lead/sessions:
|
|
get:
|
|
operationId: listLeadSessions
|
|
description: The calling user's lead agent sessions, oldest first. A compaction completes one and starts the next.
|
|
responses:
|
|
"200":
|
|
description: The sessions.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AgentSession" }
|
|
|
|
/api/me/lead/messages:
|
|
post:
|
|
operationId: messageLead
|
|
description: >
|
|
Sends a message to the calling user's lead agent, starting a lead session when there is none.
|
|
While the lead is mid-turn the message is held and sent as its next turn.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/MessageCreate" }
|
|
responses:
|
|
"202":
|
|
description: The lead session the message went to or is held for.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/focus:
|
|
get:
|
|
operationId: getFocus
|
|
responses:
|
|
"200":
|
|
description: What the calling user's right pane shows.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Focus" }
|
|
put:
|
|
operationId: setFocus
|
|
description: Records the human switching the right pane's project, task or tab.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Focus" }
|
|
responses:
|
|
"200":
|
|
description: The stored focus.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Focus" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/me/pane-focus:
|
|
put:
|
|
operationId: setPaneFocus
|
|
description: Records whether the human is working in the right pane. While they are, the lead agent can't move it.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/PaneFocus" }
|
|
responses:
|
|
"204":
|
|
description: Recorded.
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects:
|
|
get:
|
|
operationId: listProjects
|
|
responses:
|
|
"200":
|
|
description: All projects.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Project" }
|
|
post:
|
|
operationId: createProject
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/ProjectCreate" }
|
|
responses:
|
|
"201":
|
|
description: The new project.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Project" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getProject
|
|
responses:
|
|
"200":
|
|
description: The project.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Project" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}/tasks:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listTasks
|
|
responses:
|
|
"200":
|
|
description: The project's tasks, newest first.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
post:
|
|
operationId: createTask
|
|
description: Creates the task's branch and worktree from the project's default branch.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TaskCreate" }
|
|
responses:
|
|
"201":
|
|
description: The new task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}/todo:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTodo
|
|
description: The items of TODO.md at the root of the project's default branch, in file order.
|
|
responses:
|
|
"200":
|
|
description: The items; exists is false when the default branch has no TODO.md.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Todo" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/projects/{projectId}/todo/tasks:
|
|
parameters:
|
|
- { name: projectId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: startTodoItem
|
|
description: >
|
|
Creates a task for a TODO.md item, recording the item as its todo_item, and starts its agent with the item as
|
|
the first message. Refused while another active task has the same item.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TodoStart" }
|
|
responses:
|
|
"201":
|
|
description: The new task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTask
|
|
responses:
|
|
"200":
|
|
description: The task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/workflow:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskWorkflow
|
|
description: >
|
|
The workflow the task froze when it was created, as it was then. Later edits and deletes of the workflow
|
|
don't change it.
|
|
responses:
|
|
"200":
|
|
description: The frozen workflow.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TaskWorkflow" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/unmerged:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getUnmerged
|
|
description: What the task's worktree holds that its project's default branch doesn't.
|
|
responses:
|
|
"200":
|
|
description: The unmerged changes.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Unmerged" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/co-authors:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getCoAuthors
|
|
description: >
|
|
The humans other than the caller with a message in the task's transcript (sent its agent a message, or had
|
|
an inbox answer delivered under their name), in order of their first message. A merge by the caller gives each one with a git identity a
|
|
Co-authored-by trailer.
|
|
responses:
|
|
"200":
|
|
description: The co-authors.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Participant" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/merge:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: mergeTask
|
|
description: >
|
|
Sets the task's merge_title to the confirmed title, then starts the same agent turn as merge-in, without
|
|
its invitation to revise the title. When that turn ends normally, byre squashes the task's worktree
|
|
into one commit titled with the task's merge_title on the project's default branch, authored by the caller with
|
|
a Co-authored-by trailer for each of the task's co-authors, pushes it to origin, fast-forwards the project's
|
|
checkout to it, then removes the worktree and branch and marks the task merged. While another task in the
|
|
project is merging, the merge is held instead (merge_queued_at is set) and starts when no merge is in progress
|
|
in the project and the task's session is idle, oldest first. The title is fixed from here until the task
|
|
closes. Refused while a turn is running, or the merge is already held.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [merge_title]
|
|
properties:
|
|
merge_title: { type: string, description: "The squash commit's title: one line, at most 72 characters." }
|
|
responses:
|
|
"202":
|
|
description: The merge was started or held.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/merge-in:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: mergeIn
|
|
description: >
|
|
Asks the task's agent to merge the project's default branch into the task branch, resolving any conflicts
|
|
and regenerating generated files. Sent to the task's idle session, or starts a session when it has none.
|
|
Refused while a turn is running.
|
|
responses:
|
|
"202":
|
|
description: The merge turn was started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/discard:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: discardTask
|
|
description: Removes the task's worktree and branch without merging. The task's record and events remain.
|
|
responses:
|
|
"200":
|
|
description: The discarded task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/events:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listTaskEvents
|
|
description: The task's events after a seq, oldest first. Page by passing the last seq back as after.
|
|
parameters:
|
|
- { name: after, in: query, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: limit, in: query, required: false, schema: { type: integer, minimum: 1, maximum: 1000 } }
|
|
responses:
|
|
"200":
|
|
description: Up to limit events (default 500).
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Event" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/changes:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskChanges
|
|
description: >
|
|
Everything in the task's worktree (committed, staged, unstaged and untracked, respecting .gitignore) as a tree,
|
|
compared with the merge-base of the task branch and the project's default branch, or with since when given.
|
|
The worktree's own index is not touched. With snapshot, the tree is that snapshot's instead, compared with the
|
|
merge-base of its commit and the default branch, or with the previous snapshot's tree when step is true.
|
|
parameters:
|
|
- { name: since, in: query, required: false, schema: { type: string }, description: "A commit to compare with instead of the merge-base, such as a user.message event's head. Not allowed with snapshot." }
|
|
- { name: snapshot, in: query, required: false, schema: { type: integer }, description: "A snapshot's n: show the task as it was in that snapshot rather than the live worktree." }
|
|
- { name: step, in: query, required: false, schema: { type: boolean }, description: "With snapshot: compare with the previous snapshot (the snapshot commit's parent for the first one)." }
|
|
responses:
|
|
"200":
|
|
description: Per-file stats.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TaskChanges" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/image:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskImage
|
|
description: >
|
|
An image file from the task's worktree, for Markdown images and image attachments. path is absolute or relative
|
|
to the worktree; after resolving symlinks it must be inside the worktree. PNG, JPEG, GIF, WebP and SVG, chosen by extension.
|
|
parameters:
|
|
- { name: path, in: query, required: true, schema: { type: string } }
|
|
responses:
|
|
"200":
|
|
description: The file's bytes.
|
|
content:
|
|
image/png: { schema: { type: string, format: binary } }
|
|
image/jpeg: { schema: { type: string, format: binary } }
|
|
image/gif: { schema: { type: string, format: binary } }
|
|
image/webp: { schema: { type: string, format: binary } }
|
|
image/svg+xml: { schema: { type: string, format: binary } }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"403": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/diff:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskDiff
|
|
description: The unified diff of one file between a base and tree from getTaskChanges.
|
|
parameters:
|
|
- { name: base, in: query, required: true, schema: { type: string } }
|
|
- { name: tree, in: query, required: true, schema: { type: string } }
|
|
- { name: path, in: query, required: true, schema: { type: string } }
|
|
- { name: old_path, in: query, required: false, schema: { type: string } }
|
|
responses:
|
|
"200":
|
|
description: The patch.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/FileDiff" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/dir:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskDir
|
|
description: >
|
|
One directory of the task's worktree, directories first, then by name. Entries named .git are left out;
|
|
gitignored entries are included and marked.
|
|
A path that leaves the worktree, through .. or a symlink, is refused.
|
|
parameters:
|
|
- { name: path, in: query, required: false, schema: { type: string }, description: "Slash-separated, relative to the worktree root; empty or absent for the root." }
|
|
responses:
|
|
"200":
|
|
description: The directory's entries.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/DirListing" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/file:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskFile
|
|
description: >
|
|
A regular file in the task's worktree. Text is returned up to a size limit; binary files return no content.
|
|
A path that leaves the worktree, through .. or a symlink, is refused.
|
|
parameters:
|
|
- { name: path, in: query, required: true, schema: { type: string }, description: "Slash-separated, relative to the worktree root." }
|
|
responses:
|
|
"200":
|
|
description: The file.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/FileContent" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/terminal:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getTaskTerminal
|
|
description: >
|
|
A WebSocket attached to the task's terminal, a login shell in its worktree, started at cols by rows if none is
|
|
running. The server first sends what the terminal has recently printed, then its output as it comes, all as
|
|
binary messages. The client sends input as binary messages and resizes as text messages holding a
|
|
TerminalSize. When the shell exits the server closes with code 4000 and the exit status as the reason.
|
|
parameters:
|
|
- { name: cols, in: query, required: true, schema: { type: integer, minimum: 1 } }
|
|
- { name: rows, in: query, required: true, schema: { type: integer, minimum: 1 } }
|
|
responses:
|
|
"101":
|
|
description: Switched to the WebSocket protocol.
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/previews:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listPreviews
|
|
description: >
|
|
The ports the task's agent exposed with expose_port, by name. Each is served by tailscale serve on the same
|
|
port number of byre's host, over HTTPS, until the task is merged or discarded.
|
|
responses:
|
|
"200":
|
|
description: The previews.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Preview" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/snapshots:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listSnapshots
|
|
description: >
|
|
The task's snapshots, oldest first. Each is a commit of the worktree as if everything were staged, kept at
|
|
refs/byre/tasks/{taskId}/snap/{n} until the task is merged or discarded; the rows remain after that.
|
|
responses:
|
|
"200":
|
|
description: The snapshots.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Snapshot" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/reviews:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listReviews
|
|
description: The task's reviews, one per snapshot, oldest first.
|
|
responses:
|
|
"200":
|
|
description: The reviews.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Review" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/snapshots/{n}/fork:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
- { name: n, in: path, required: true, schema: { type: integer } }
|
|
post:
|
|
operationId: forkSnapshot
|
|
description: >
|
|
Creates a new task whose branch and worktree start from the snapshot's commit, with an idle agent session that
|
|
continues the snapshot's agent conversation as it stood at the snapshot (the vendor's own session fork). The
|
|
new session's first turn is the first message sent to it. Refused while the task is closed, and for a snapshot
|
|
with no recorded agent message at or before it.
|
|
responses:
|
|
"201":
|
|
description: The new task.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Task" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/tasks/{taskId}/sessions:
|
|
parameters:
|
|
- { name: taskId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: listSessions
|
|
responses:
|
|
"200":
|
|
description: The task's agent sessions, oldest first.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
post:
|
|
operationId: createSession
|
|
description: Starts an agent session in the task's worktree and sends it the prompt as its first turn.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/SessionCreate" }
|
|
responses:
|
|
"201":
|
|
description: The new session.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getSession
|
|
responses:
|
|
"200":
|
|
description: The session.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}/messages:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: sendMessage
|
|
description: Starts a new turn with this message when the session is idle. While a task session's turn is running, the message is queued and reaches the agent after its next tool call, or as the next turn.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/MessageCreate" }
|
|
responses:
|
|
"202":
|
|
description: The turn has started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}/compact:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: compactSession
|
|
description: >
|
|
Asks the idle session's agent for a handoff (goal, decisions, state, dead ends, open questions, files). When that turn ends,
|
|
the session is completed and a new session on the same task and model starts with the handoff as its first message.
|
|
responses:
|
|
"202":
|
|
description: The handoff turn was started.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/sessions/{sessionId}/interrupt:
|
|
parameters:
|
|
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
post:
|
|
operationId: interruptSession
|
|
description: Ends the current turn.
|
|
responses:
|
|
"202":
|
|
description: The interrupt was delivered.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AgentSession" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/blobs:
|
|
post:
|
|
operationId: uploadBlob
|
|
description: >
|
|
Stores an image for use in a message. The body is the raw image; its type is detected from the bytes
|
|
and must be PNG, JPEG, GIF or WebP. At most 5 MiB.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
image/png: { schema: { type: string, format: binary } }
|
|
image/jpeg: { schema: { type: string, format: binary } }
|
|
image/gif: { schema: { type: string, format: binary } }
|
|
image/webp: { schema: { type: string, format: binary } }
|
|
responses:
|
|
"201":
|
|
description: The stored blob.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Blob" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"413": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/blobs/{blobId}:
|
|
parameters:
|
|
- { name: blobId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getBlob
|
|
responses:
|
|
"200":
|
|
description: The blob's bytes, with its content type.
|
|
content:
|
|
image/png: { schema: { type: string, format: binary } }
|
|
image/jpeg: { schema: { type: string, format: binary } }
|
|
image/gif: { schema: { type: string, format: binary } }
|
|
image/webp: { schema: { type: string, format: binary } }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/inbox:
|
|
get:
|
|
operationId: listInbox
|
|
description: >
|
|
Inbox items, oldest first.
|
|
Filters narrow the one query to a project's or a task's view.
|
|
parameters:
|
|
- { name: project_id, in: query, required: false, schema: { type: string } }
|
|
- { name: task_id, in: query, required: false, schema: { type: string } }
|
|
- { name: state, in: query, required: false, schema: { $ref: "#/components/schemas/InboxState" } }
|
|
responses:
|
|
"200":
|
|
description: Matching items with their responses. Defaults to open items.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/InboxItem" }
|
|
|
|
/api/inbox/{itemId}:
|
|
parameters:
|
|
- { name: itemId, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getInboxItem
|
|
responses:
|
|
"200":
|
|
description: The item with its responses.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/InboxItem" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/inbox/responses:
|
|
post:
|
|
operationId: respondInbox
|
|
description: >
|
|
Answers one or more items in one submission. Answers reach the agent as one message once
|
|
it is idle and none of its questions are unanswered.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/InboxRespond" }
|
|
responses:
|
|
"200":
|
|
description: The updated items.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/InboxItem" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/events:
|
|
get:
|
|
operationId: streamEvents
|
|
description: >
|
|
Server-sent events. Each event's id is its seq; data is the Event as JSON.
|
|
Events after Last-Event-ID (or the after query parameter) are replayed before live events.
|
|
With task_id, only that task's events are sent; with lead=true, only the events of the caller's lead agent.
|
|
Events with an owner go only to that user.
|
|
parameters:
|
|
- { name: Last-Event-ID, in: header, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: after, in: query, required: false, schema: { type: integer, format: int64 } }
|
|
- { name: task_id, in: query, required: false, schema: { type: string } }
|
|
- { name: lead, in: query, required: false, schema: { type: boolean } }
|
|
responses:
|
|
"200":
|
|
description: Event stream.
|
|
content:
|
|
text/event-stream:
|
|
schema: { type: string }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
/api/admin/status:
|
|
get:
|
|
operationId: getStatus
|
|
responses:
|
|
"200":
|
|
description: Server health and usage.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Status" }
|
|
|
|
/api/workflows:
|
|
get:
|
|
operationId: listWorkflows
|
|
responses:
|
|
"200":
|
|
description: Every workflow's name and description, by name.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/WorkflowSummary" }
|
|
|
|
/api/workflows/{name}:
|
|
parameters:
|
|
- { name: name, in: path, required: true, schema: { type: string } }
|
|
get:
|
|
operationId: getWorkflow
|
|
responses:
|
|
"200":
|
|
description: "The workflow's file: its WorkflowDefinition as YAML, as an attachment named after it."
|
|
content:
|
|
application/yaml:
|
|
schema: { type: string }
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
put:
|
|
operationId: putWorkflow
|
|
description: >
|
|
Creates or replaces the workflow from its file, a WorkflowDefinition as YAML (or JSON). The name is one line
|
|
of 1 to 100 characters. Tasks that already froze the workflow keep their copy.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/yaml:
|
|
schema: { type: string }
|
|
responses:
|
|
"200":
|
|
description: The stored workflow.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/WorkflowSummary" }
|
|
"400": { $ref: "#/components/responses/Error" }
|
|
delete:
|
|
operationId: deleteWorkflow
|
|
responses:
|
|
"204":
|
|
description: Deleted. Tasks that froze it keep their copy.
|
|
"404": { $ref: "#/components/responses/Error" }
|
|
|
|
components:
|
|
responses:
|
|
Error:
|
|
description: Error.
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/Error" }
|
|
|
|
schemas:
|
|
Error:
|
|
type: object
|
|
required: [message]
|
|
properties:
|
|
message: { type: string }
|
|
|
|
User:
|
|
type: object
|
|
required: [login, display_name, git_name, git_email, notification_prefs]
|
|
properties:
|
|
login: { type: string }
|
|
display_name: { type: string }
|
|
git_name: { type: string }
|
|
git_email: { type: string }
|
|
notification_prefs: { $ref: "#/components/schemas/NotificationPrefs" }
|
|
|
|
NotificationPrefs:
|
|
type: object
|
|
description: Which new inbox items and finished turns notify this user in their open byre pages.
|
|
required: [questions, reports, errors, rate_limits]
|
|
properties:
|
|
questions: { type: boolean, description: Questions. On by default. }
|
|
reports: { type: boolean, description: "Task turns that end with a summary (turn.ended with summary: true)." }
|
|
errors: { type: boolean, description: session_error items. }
|
|
rate_limits: { type: boolean, description: rate_limited items. }
|
|
|
|
UserUpdate:
|
|
type: object
|
|
required: [git_name, git_email]
|
|
properties:
|
|
git_name: { type: string }
|
|
git_email: { type: string }
|
|
|
|
Project:
|
|
type: object
|
|
required: [id, name, repo_path, default_branch, remote, created_by, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
name: { type: string }
|
|
repo_path: { type: string }
|
|
default_branch: { type: string }
|
|
remote: { type: string }
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
ProjectCreate:
|
|
type: object
|
|
required: [name, repo_path]
|
|
properties:
|
|
name: { type: string }
|
|
repo_path: { type: string }
|
|
|
|
Task:
|
|
type: object
|
|
required: [id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, reviewing]
|
|
properties:
|
|
id: { type: string }
|
|
project_id: { type: string }
|
|
title: { type: string }
|
|
merge_title: { type: string, description: "The title of the squash commit Merge makes: the task title until the agent sets another with set_merge_title." }
|
|
branch: { type: string }
|
|
worktree_path: { type: string }
|
|
base_ref: { type: string }
|
|
port_base: { type: integer, description: "The first of the task's block of ports (port_base to port_base+9), passed to its agent and terminal as PORT." }
|
|
color: { type: integer, description: "Index into the UI's task palette, assigned at creation: a colour no active task holds, the one given out longest ago." }
|
|
status:
|
|
type: string
|
|
enum: [active, merged, discarded]
|
|
x-enum-varnames: [TaskStatusActive, TaskStatusMerged, TaskStatusDiscarded]
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
closed_at: { type: string, format: date-time, description: When the task was merged or discarded. }
|
|
merge_commit: { type: string, description: "merged: the squash commit on the default branch; empty when there was nothing to merge." }
|
|
todo_item: { type: string, description: "The title of the TODO.md item the task was started from; absent for other tasks." }
|
|
forked_from: { type: string, description: "The task this one was forked from; absent for other tasks." }
|
|
forked_at: { type: integer, description: "With forked_from: the n of the snapshot it was forked at." }
|
|
merge_queued_at: { type: string, format: date-time, description: "When Merge was requested while another task in the project was merging; absent once the merge starts or when none is held." }
|
|
workflow: { type: string, description: "The name of the workflow the task froze at creation (getTaskWorkflow has its copy); absent for a task without one." }
|
|
workflow_run: { type: string, description: "With workflow: the id every task of one run of the workflow shares." }
|
|
workflow_stage: { type: string, description: "With workflow: the name of the stage this task runs." }
|
|
reviewing: { type: boolean, description: "Whether a review of one of the task's snapshots is running." }
|
|
|
|
Todo:
|
|
type: object
|
|
required: [exists, items]
|
|
properties:
|
|
exists: { type: boolean, description: Whether the default branch has a TODO.md at its root. }
|
|
items:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/TodoItem" }
|
|
|
|
TodoItem:
|
|
type: object
|
|
required: [title, body, section]
|
|
properties:
|
|
title: { type: string, description: "The item's first line, without its list marker: the item's identity." }
|
|
body: { type: string, description: The item's further lines, as Markdown with the item's indentation removed. }
|
|
section: { type: string, description: The text of the nearest heading above the item; empty when there is none. }
|
|
|
|
TodoStart:
|
|
type: object
|
|
required: [title]
|
|
properties:
|
|
title: { type: string, description: The title of the item to start. }
|
|
model: { type: string }
|
|
discuss: { type: boolean, description: "Tell the agent the human wants to talk the item through, so it asks before changing anything." }
|
|
|
|
Unmerged:
|
|
type: object
|
|
required: [commits, files, insertions, deletions, uncommitted]
|
|
properties:
|
|
commits: { type: integer, description: Commits on the task branch that aren't on the default branch. }
|
|
files: { type: integer, description: Files that differ from the merge base, uncommitted changes included. }
|
|
insertions: { type: integer }
|
|
deletions: { type: integer }
|
|
uncommitted: { type: integer, description: Paths with uncommitted changes in the worktree. }
|
|
|
|
Participant:
|
|
type: object
|
|
required: [login, display_name, git_name, git_email]
|
|
properties:
|
|
login: { type: string }
|
|
display_name: { type: string }
|
|
git_name: { type: string, description: Empty when the user hasn't set a git identity; they then get no trailer. }
|
|
git_email: { type: string }
|
|
|
|
TaskCreate:
|
|
type: object
|
|
required: [title]
|
|
properties:
|
|
title: { type: string }
|
|
|
|
WorkflowSummary:
|
|
type: object
|
|
required: [name, description]
|
|
properties:
|
|
name: { type: string }
|
|
description: { type: string }
|
|
|
|
WorkflowDefinition:
|
|
type: object
|
|
description: >
|
|
A workflow's file, which holds everything but its name: its stages, each run as its own task once the stages
|
|
it comes after have finished. Sent and returned as YAML.
|
|
required: [stages]
|
|
properties:
|
|
description: { type: string, x-go-type-skip-optional-pointer: true }
|
|
stages:
|
|
type: array
|
|
minItems: 1
|
|
items: { $ref: "#/components/schemas/Stage" }
|
|
|
|
Stage:
|
|
type: object
|
|
required: [name, model, prompt]
|
|
properties:
|
|
name: { type: string, description: "One line of 1 to 100 characters, unique within the workflow." }
|
|
after:
|
|
type: array
|
|
items: { type: string }
|
|
description: >
|
|
The stages whose outputs this stage gets, by name; it starts once all of them have finished. Absent means
|
|
the previous stage in the list (for the first stage, none); empty means it starts from the brief.
|
|
base:
|
|
type: string
|
|
enum: [parent, main]
|
|
x-enum-varnames: [StageBaseParent, StageBaseMain]
|
|
description: >
|
|
Where the stage's task branches from. parent (the default): the commit its one after stage finished at, or
|
|
for a stage with none, where the workflow was started from. main: the project's default branch. Refused on
|
|
a stage with more than one after stage, which always branches from the default branch.
|
|
model: { type: string, description: "The stage agent's model, which also picks its vendor: gpt-* models run on Codex, every other model on Claude Code." }
|
|
prompt: { type: string, description: "The stage agent's instructions." }
|
|
|
|
TaskWorkflow:
|
|
type: object
|
|
description: The workflow a task froze when it was created, as it was then.
|
|
required: [name, definition]
|
|
properties:
|
|
name: { type: string }
|
|
definition: { type: string, description: The WorkflowDefinition as YAML. }
|
|
|
|
TaskChanges:
|
|
type: object
|
|
required: [base, tree, files]
|
|
properties:
|
|
base: { type: string, description: "The commit or tree compared with: the merge-base of the task branch and the default branch, since, or the previous snapshot's tree." }
|
|
tree: { type: string, description: "Tree of the worktree as if everything were staged, or the snapshot's tree." }
|
|
files:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/FileChange" }
|
|
|
|
FileChange:
|
|
type: object
|
|
required: [path, status, additions, deletions, binary]
|
|
properties:
|
|
path: { type: string }
|
|
old_path: { type: string, description: "renamed: the path before the rename." }
|
|
status: { type: string, enum: [added, modified, deleted, renamed, type_changed] }
|
|
additions: { type: integer }
|
|
deletions: { type: integer }
|
|
binary: { type: boolean }
|
|
|
|
FileDiff:
|
|
type: object
|
|
required: [path, patch]
|
|
properties:
|
|
path: { type: string }
|
|
patch: { type: string }
|
|
|
|
DirListing:
|
|
type: object
|
|
required: [path, entries, truncated]
|
|
properties:
|
|
path: { type: string, description: "The directory, relative to the worktree root; empty for the root." }
|
|
entries:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/DirEntry" }
|
|
truncated: { type: boolean, description: The directory has more entries than were returned. }
|
|
|
|
DirEntry:
|
|
type: object
|
|
required: [name, type, symlink, size, ignored]
|
|
properties:
|
|
name: { type: string }
|
|
ignored: { type: boolean, description: "git ignores the entry: .gitignore and the other exclude files match it or a directory above it." }
|
|
type:
|
|
type: string
|
|
enum: [dir, file, other]
|
|
x-enum-varnames: [DirEntryTypeDir, DirEntryTypeFile, DirEntryTypeOther]
|
|
description: "What the entry is, following a symlink that stays in the worktree. other: a symlink that leaves the worktree or points nowhere, or a device, socket or pipe."
|
|
symlink: { type: boolean }
|
|
size: { type: integer, format: int64, description: "file: its size in bytes." }
|
|
|
|
FileContent:
|
|
type: object
|
|
required: [path, size, binary, truncated, text]
|
|
properties:
|
|
path: { type: string }
|
|
size: { type: integer, format: int64 }
|
|
binary: { type: boolean, description: The file isn't UTF-8 text; text is empty. }
|
|
truncated: { type: boolean, description: "text holds only the start of the file." }
|
|
text: { type: string }
|
|
|
|
Snapshot:
|
|
type: object
|
|
required: [id, task_id, agent_session_id, n, commit_sha, tree_sha, event_seq, trigger, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
task_id: { type: string }
|
|
agent_session_id: { type: string }
|
|
n: { type: integer, description: "Position in the task's snapshots, from 1; the ref is refs/byre/tasks/{task_id}/snap/{n}." }
|
|
commit_sha: { type: string, description: A commit of tree_sha whose parent is the worktree's HEAD when it was taken. }
|
|
tree_sha: { type: string }
|
|
event_seq: { type: integer, format: int64, description: "The task's latest event when the snapshot was started: the tree holds at least the work up to it." }
|
|
trigger:
|
|
type: string
|
|
enum: [message, turn_end, tool_call, ask_human, timer]
|
|
x-enum-varnames: [SnapshotTriggerMessage, SnapshotTriggerTurnEnd, SnapshotTriggerToolCall, SnapshotTriggerAskHuman, SnapshotTriggerTimer]
|
|
description: "turn_end: after byre's end-of-turn commit. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds."
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Preview:
|
|
type: object
|
|
required: [task_id, name, port, created_at]
|
|
properties:
|
|
task_id: { type: string }
|
|
name: { type: string }
|
|
port: { type: integer, description: "A port in the task's block, served at https://<byre's host>:<port>/." }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Review:
|
|
type: object
|
|
description: An agent session on the vendor the task's agent doesn't use, reviewing one snapshot's change.
|
|
required: [id, task_id, snapshot_n, agent_session_id, vendor, model, state, error, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
task_id: { type: string }
|
|
snapshot_n: { type: integer }
|
|
agent_session_id: { type: string, description: "The reviewer's session; empty when skipped." }
|
|
vendor: { type: string, description: "Empty when skipped." }
|
|
model: { type: string, description: "Empty when skipped." }
|
|
state:
|
|
type: string
|
|
enum: [running, done, failed, skipped]
|
|
x-enum-varnames: [ReviewStateRunning, ReviewStateDone, ReviewStateFailed, ReviewStateSkipped]
|
|
description: "skipped: the snapshot's step changed no files, so no reviewer ran."
|
|
result: { type: object, description: "done: the reviewer's submit_review arguments: summary (Markdown) and findings, each with severity, category, title, detail, path and line." }
|
|
error: { type: string, description: "failed: why." }
|
|
created_at: { type: string, format: date-time }
|
|
finished_at: { type: string, format: date-time }
|
|
|
|
AgentSession:
|
|
type: object
|
|
required: [id, task_id, owner, vendor, model, vendor_session_id, state, role, created_by, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
task_id: { type: string, description: Empty for a lead session. }
|
|
owner: { type: string, description: "The login whose lead agent this is; empty for a task's session." }
|
|
vendor: { type: string, enum: [claude, codex], description: "Follows from the model the session was created with: gpt-* models run on Codex, every other model on Claude Code." }
|
|
model: { type: string, description: "Requested model; empty means the vendor's default. A session only switches between its own vendor's models." }
|
|
vendor_session_id: { type: string, description: "Claude Code's session id, chosen by byre; or the Codex thread id, empty until the session's first turn starts its thread." }
|
|
state:
|
|
type: string
|
|
enum: [idle, running, completed]
|
|
x-enum-varnames: [AgentSessionStateIdle, AgentSessionStateRunning, AgentSessionStateCompleted]
|
|
role: { type: string, enum: [implementer, lead, reviewer], description: "reviewer: a review's session (see Review); a task's sessions list leaves these out." }
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
forked_from: { type: string, description: "A fork's first start resumes this vendor session, cut at forked_at, under a new vendor_session_id; absent for other sessions." }
|
|
forked_at: { type: string, description: "With forked_from: the vendor's id of the last thing the fork keeps, a message for Claude Code, a turn for Codex." }
|
|
SessionCreate:
|
|
type: object
|
|
required: [prompt]
|
|
properties:
|
|
prompt: { type: string }
|
|
model: { type: string }
|
|
images:
|
|
type: array
|
|
items: { type: string }
|
|
description: Blob ids from uploadBlob, sent to the agent as images alongside the prompt.
|
|
|
|
MessageCreate:
|
|
type: object
|
|
required: [text]
|
|
properties:
|
|
text: { type: string, description: May be empty when images are given. }
|
|
images:
|
|
type: array
|
|
items: { type: string }
|
|
description: Blob ids from uploadBlob, sent to the agent as images alongside the text.
|
|
model:
|
|
type: string
|
|
description: Model for this turn and later ones. When it differs from the session's model, the session switches before the message is sent.
|
|
|
|
Blob:
|
|
type: object
|
|
required: [id, content_type, created_by, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
content_type: { type: string }
|
|
created_by: { type: string }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Attachment:
|
|
type: object
|
|
required: [kind]
|
|
properties:
|
|
kind: { type: string, enum: [file, diff, image, diagram, task, snapshot, url] }
|
|
path: { type: string, description: "file: repo-relative path. image: an image file in the task's worktree, absolute or relative to it." }
|
|
start_line: { type: integer }
|
|
end_line: { type: integer }
|
|
ref: { type: string, description: "diff: git revision range." }
|
|
url: { type: string }
|
|
mermaid: { type: string, description: "diagram: Mermaid source." }
|
|
image: { type: string, description: "image: data URL." }
|
|
task_id: { type: string }
|
|
snapshot_id: { type: string }
|
|
caption: { type: string }
|
|
|
|
InboxState:
|
|
type: string
|
|
enum: [open, answered, dismissed, superseded]
|
|
|
|
InboxItem:
|
|
type: object
|
|
required: [id, project_id, task_id, agent_session_id, thread_id, kind, payload, state, created_at, responses, reviews]
|
|
properties:
|
|
id: { type: string }
|
|
project_id: { type: string }
|
|
task_id: { type: string }
|
|
agent_session_id: { type: string }
|
|
thread_id: { type: string }
|
|
kind: { type: string, enum: [question, session_error, rate_limited] }
|
|
payload:
|
|
type: object
|
|
description: >
|
|
question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items),
|
|
question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments.
|
|
session_error: error.
|
|
rate_limited: vendor, rate_limit (the vendor's rate-limit status), error.
|
|
state: { $ref: "#/components/schemas/InboxState" }
|
|
reviews:
|
|
type: array
|
|
description: "question: the review of the first snapshot the task took after the question was asked (the snapshot at the end of the turn that asked it), once that snapshot exists; empty for other items."
|
|
items: { $ref: "#/components/schemas/Review" }
|
|
created_at: { type: string, format: date-time }
|
|
resolved_by: { type: string }
|
|
resolved_at: { type: string, format: date-time }
|
|
responses:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/InboxResponse" }
|
|
|
|
InboxResponseType:
|
|
type: string
|
|
enum: [option, other, dismiss]
|
|
|
|
InboxResponse:
|
|
type: object
|
|
required: [id, item_id, user, type, attachments, created_at]
|
|
properties:
|
|
id: { type: string }
|
|
item_id: { type: string }
|
|
user: { type: string }
|
|
type: { $ref: "#/components/schemas/InboxResponseType" }
|
|
options:
|
|
type: array
|
|
items: { type: string }
|
|
text: { type: string }
|
|
attachments:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Attachment" }
|
|
created_at: { type: string, format: date-time }
|
|
delivered_at: { type: string, format: date-time }
|
|
|
|
InboxResponseCreate:
|
|
type: object
|
|
required: [item_id, type]
|
|
properties:
|
|
item_id: { type: string }
|
|
type: { $ref: "#/components/schemas/InboxResponseType" }
|
|
options:
|
|
type: array
|
|
items: { type: string }
|
|
description: "option: the chosen options; exactly one for a pick-one question, one or more for a pick-any question."
|
|
text: { type: string, description: "other: the text sent to the agent. option on a pick-any question: optional text sent along with the checked options." }
|
|
attachments:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/Attachment" }
|
|
|
|
InboxRespond:
|
|
type: object
|
|
required: [responses]
|
|
properties:
|
|
responses:
|
|
type: array
|
|
minItems: 1
|
|
items: { $ref: "#/components/schemas/InboxResponseCreate" }
|
|
|
|
Event:
|
|
type: object
|
|
required: [seq, kind, actor, payload, created_at]
|
|
properties:
|
|
seq: { type: integer, format: int64 }
|
|
kind: { type: string }
|
|
project_id: { type: string }
|
|
task_id: { type: string }
|
|
agent_session_id: { type: string }
|
|
owner: { type: string, description: "Set on a lead agent's events and a user's focus.updated: the login they belong to. Only that user is sent them." }
|
|
actor: { type: string }
|
|
payload: { type: object }
|
|
created_at: { type: string, format: date-time }
|
|
|
|
Focus:
|
|
type: object
|
|
required: [tabs, tab]
|
|
properties:
|
|
project_id: { type: string, description: The project the right pane shows; the task's project when task_id is set, absent for none. }
|
|
task_id: { type: string, description: The task the right pane shows; absent for none. }
|
|
tabs:
|
|
type: array
|
|
description: The tabs the lead put first, in order. The other task tabs follow them.
|
|
items: { $ref: "#/components/schemas/TaskTab" }
|
|
tab: { $ref: "#/components/schemas/TaskTab" }
|
|
|
|
PaneFocus:
|
|
type: object
|
|
required: [focused]
|
|
properties:
|
|
focused: { type: boolean, description: True while the browser window has focus and the focused element is inside the right pane. }
|
|
|
|
TaskTab:
|
|
type: string
|
|
enum: [transcript, changes, files, terminal, inbox, reviews, project]
|
|
x-enum-varnames: [TabTranscript, TabChanges, TabFiles, TabTerminal, TabInbox, TabReviews, TabProject]
|
|
|
|
TerminalSize:
|
|
type: object
|
|
required: [cols, rows]
|
|
properties:
|
|
cols: { type: integer, minimum: 1 }
|
|
rows: { type: integer, minimum: 1 }
|
|
|
|
Status:
|
|
type: object
|
|
required: [started_at, db_bytes, last_event_seq, projects, active_tasks, sse_clients, live_agents, running_turns, rate_limits, agent_processes, zombies, stuck_after_seconds, protocol_errors]
|
|
properties:
|
|
live_agents: { type: integer, description: Agent processes currently running. }
|
|
agent_processes:
|
|
type: array
|
|
description: Every agent process byre is tracking, idle sessions included.
|
|
items: { $ref: "#/components/schemas/AgentProcess" }
|
|
zombies:
|
|
type: array
|
|
description: Sessions marked running with no live process, and agent processes byre has no session for.
|
|
items: { $ref: "#/components/schemas/Zombie" }
|
|
stuck_after_seconds: { type: integer, description: How long a running turn may go without a stream event before it counts as stuck. }
|
|
protocol_errors: { $ref: "#/components/schemas/ProtocolErrors" }
|
|
running_turns:
|
|
type: array
|
|
description: Turns running now, oldest session first.
|
|
items: { $ref: "#/components/schemas/TurnRef" }
|
|
rate_limits:
|
|
type: object
|
|
description: The latest rate-limit status each vendor reported, keyed by vendor.
|
|
additionalProperties: { type: object }
|
|
started_at: { type: string, format: date-time }
|
|
db_bytes: { type: integer, format: int64 }
|
|
last_event_seq: { type: integer, format: int64 }
|
|
projects: { type: integer }
|
|
active_tasks: { type: integer }
|
|
sse_clients: { type: integer }
|
|
|
|
TurnRef:
|
|
type: object
|
|
required: [session_id, task_id, vendor]
|
|
properties:
|
|
session_id: { type: string }
|
|
task_id: { type: string }
|
|
vendor: { type: string }
|
|
|
|
AgentProcess:
|
|
type: object
|
|
required: [session_id, task_id, vendor, pid, state, last_event_at, health]
|
|
properties:
|
|
session_id: { type: string }
|
|
task_id: { type: string }
|
|
vendor: { type: string }
|
|
pid: { type: integer }
|
|
state: { type: string, description: The session's state, as on AgentSession. }
|
|
last_event_at: { type: string, format: date-time, description: When the process last wrote a line to its stream, or when it started. }
|
|
health:
|
|
type: string
|
|
enum: [ok, stuck, exited]
|
|
x-enum-varnames: [HealthOk, HealthStuck, HealthExited]
|
|
description: stuck means a turn is running and no stream event has arrived for stuck_after_seconds; exited means the process is gone.
|
|
|
|
Zombie:
|
|
type: object
|
|
required: [kind, detail]
|
|
properties:
|
|
kind:
|
|
type: string
|
|
enum: [running_without_process, process_without_session]
|
|
detail: { type: string }
|
|
session_id: { type: string }
|
|
task_id: { type: string }
|
|
pid: { type: integer }
|
|
|
|
ProtocolErrors:
|
|
type: object
|
|
required: [counts, recent]
|
|
properties:
|
|
counts:
|
|
type: object
|
|
description: Stream lines the adapter couldn't parse or didn't recognise since byre started, keyed by vendor.
|
|
additionalProperties: { type: integer }
|
|
recent:
|
|
type: array
|
|
description: The most recent ones, newest first.
|
|
items: { $ref: "#/components/schemas/ProtocolError" }
|
|
|
|
ProtocolError:
|
|
type: object
|
|
required: [vendor, session_id, at, reason, raw, size]
|
|
properties:
|
|
vendor: { type: string }
|
|
session_id: { type: string }
|
|
at: { type: string, format: date-time }
|
|
reason: { type: string }
|
|
raw: { type: string, description: The line as received, cut to its first 4 KiB. }
|
|
size: { type: integer, description: The line's full length in bytes. }
|