Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@

# ========== Tasks ==========
/tasks:
get:

Check warning on line 169 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: List tasks
operationId: listTasks
Expand Down Expand Up @@ -194,7 +194,7 @@
schema: {$ref: '#/components/schemas/RbacDenied'}
'429': {$ref: '#/components/responses/RateLimited'}

post:

Check warning on line 197 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Create download task
operationId: createTask
Expand Down Expand Up @@ -296,7 +296,7 @@
parameters:
- $ref: '#/components/parameters/TaskId'

get:

Check warning on line 299 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Get task by ID
operationId: getTask
Expand All @@ -315,7 +315,7 @@
'404':
description: Task not found or cross-tenant ID (existence not leaked)

patch:

Check warning on line 318 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Update task (priority only)
operationId: updateTask
Expand Down Expand Up @@ -368,7 +368,7 @@
/tasks/{taskId}/cancel:
parameters:
- $ref: '#/components/parameters/TaskId'
post:

Check warning on line 371 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Cancel task (async)
operationId: cancelTask
Expand Down Expand Up @@ -402,7 +402,7 @@
/tasks/{taskId}/retry:
parameters:
- $ref: '#/components/parameters/TaskId'
post:

Check warning on line 405 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Retry failed subtasks
operationId: retrySubtasks
Expand Down Expand Up @@ -448,7 +448,7 @@
/tasks/{taskId}/upgrade:
parameters:
- $ref: '#/components/parameters/TaskId'
post:

Check warning on line 451 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Upgrade to new revision (incremental)
operationId: upgradeTask
Expand All @@ -472,7 +472,7 @@
/tasks/{taskId}/subtasks:
parameters:
- $ref: '#/components/parameters/TaskId'
get:

Check warning on line 475 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [subtasks]
summary: List subtasks of a task
operationId: listSubtasks
Expand All @@ -495,7 +495,7 @@
/tasks/{taskId}/source-allocation:
parameters:
- $ref: '#/components/parameters/TaskId'
get:

Check warning on line 498 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: View source allocation (multi-source visualization)
operationId: getSourceAllocation
Expand All @@ -509,7 +509,7 @@
/tasks/{taskId}/events:
parameters:
- $ref: '#/components/parameters/TaskId'
get:

Check warning on line 512 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Task event log
operationId: getTaskEvents
Expand All @@ -529,6 +529,25 @@
items: {$ref: '#/components/schemas/TaskEvent'}
next_cursor: {type: string, nullable: true}

/tasks/{taskId}/stream:
parameters:
- $ref: '#/components/parameters/TaskId'
get:
tags: [tasks]
summary: Live TaskDetail SSE stream (UI-SP5)
operationId: streamTaskDetail
responses:
'200':
description: SSE stream of TaskDetail snapshots (text/event-stream)
content:
text/event-stream:
schema:
type: string
description: |
Each event is `data: <TaskDetail JSON>\n\n`. Stream terminates
on terminal task status, client disconnect, or controller
shutdown. Keep-alive comment lines (`:keepalive`) may appear.

/tasks/{taskId}/subtask-chunks:
parameters:
- $ref: '#/components/parameters/TaskId'
Expand Down
37 changes: 37 additions & 0 deletions docs/operator/web-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,40 @@ drain/restart, metrics history, heartbeat history; HF-token rotation;
license-policy CRUD; source-driver registration; maintenance mode;
`/quota/usage` (declared but no backing tables); ML forecast; chargeback PDF;
real-time audit tail (UI-SP5).

## UI-SP5 — Realtime SSE swap (delivered)

`useLiveResource` now supports an opt-in SSE transport. The locked promise
recorded in SP1/SP2/SP3 — *"SP5 swaps internals to SSE/WS with zero view
changes"* — is honored: every view, page, and other composable is unchanged.

- **Backend**: `GET /api/v1/tasks/{id}/stream` — hand-rolled
`text/event-stream` via FastAPI `StreamingResponse` (same idiom as
`hf_proxy.py`). 1 Hz default tick rate (env
`DLW_TASK_STREAM_INTERVAL_SECONDS` overrides; clamped `[0.1, 10.0]`).
Tenant-scoped via the proven cancel-pattern (404 cross-tenant). Terminates
on terminal task status, client disconnect, or controller shutdown. A
`?max_ticks=N` query param is supported for testability (httpx
`ASGITransport` buffers the response body until the generator closes, so
multi-tick tests need a natural-termination hatch).
- **Frontend**: `frontend/src/api/sse.ts` (pure `parseSseChunk` + `streamSse`
fetch + ReadableStream with exponential backoff, Bearer-via-header). The
`useLiveResource` composable gains optional `streamUrl` + `applyEvent`
fields; when both are set, the composable opens an SSE connection after
the first snapshot and writes events into the vue-query cache. On 3
consecutive failures the stream gives up and polling resumes automatically.
On 401 the streamer calls `auth.logout()`; on 403/404 it fails fast (no
backoff burn).
- **One consumer opts in**: `useTaskDetail`. Every other composable
(`useTaskList`, `useQuota`, the 4 SP2 sub-resource composables, the 3 SP3
composables) stays on polling.

**At a glance**: open `/tasks/<id>` in DevTools Network — you'll see one
long-lived `text/event-stream` connection per visit instead of a 1 Hz polling
loop.

**Deferrals**: WebSocket transport (SSE delivers the same outcome simpler);
streaming for the 4 SP2 sub-resources (would force a multi-resource envelope
that breaks view-free); SSE for the low-frequency SP3 composables (push value
is negligible at 5–30 s cadences). UI-SP4 (AI-Copilot) remains the v2.1
follow-up.
Loading
Loading