fix: include workflow in GET /api/jobs/{id} for running/pending jobs

Jobs API single-job detail lookups only embedded the workflow for
terminal (history) jobs; running and pending jobs went through
normalize_queue_item, which never carried it even though the prompt
and extra_data are already available on the queue tuple.

The frontend caches job detail responses by job id and never refetches
once cached, so opening a still-running or queued job as a workflow
failed, and stayed broken permanently once the job finished, because
the cached entry from while it was running never had a workflow to
begin with.

Fixes #14995
This commit is contained in:
Claude
2026-07-31 10:09:56 +00:00
parent e8b10ed645
commit 4a9f0663b7

View File

@@ -183,15 +183,20 @@ def is_text_preview(media_type: str, item: dict) -> bool:
return any(filename.endswith(ext) for ext in TEXT_EXTENSIONS)
def normalize_queue_item(item: tuple, status: str) -> dict:
def normalize_queue_item(item: tuple, status: str, include_workflow: bool = False) -> dict:
"""Convert queue item tuple to unified job dict.
Expects item with sensitive data already removed (5 elements).
include_workflow embeds the full prompt/extra_data (as 'workflow') the
same way normalize_history_item(include_outputs=True) does. It's only
set for single-job detail lookups (get_job), not the list endpoint,
to keep list responses lightweight.
"""
priority, prompt_id, _, extra_data, _ = item
priority, prompt_id, prompt, extra_data, _ = item
create_time, workflow_id = _extract_job_metadata(extra_data)
return prune_dict({
job = prune_dict({
'id': prompt_id,
'status': status,
'priority': priority,
@@ -200,6 +205,14 @@ def normalize_queue_item(item: tuple, status: str) -> dict:
'workflow_id': workflow_id,
})
if include_workflow:
job['workflow'] = {
'prompt': prompt,
'extra_data': extra_data,
}
return job
def normalize_history_item(prompt_id: str, history_item: dict, include_outputs: bool = False) -> dict:
"""Convert history item dict to unified job dict.
@@ -379,11 +392,11 @@ def get_job(prompt_id: str, running: list, queued: list, history: dict) -> Optio
for item in running:
if item[1] == prompt_id:
return normalize_queue_item(item, JobStatus.IN_PROGRESS)
return normalize_queue_item(item, JobStatus.IN_PROGRESS, include_workflow=True)
for item in queued:
if item[1] == prompt_id:
return normalize_queue_item(item, JobStatus.PENDING)
return normalize_queue_item(item, JobStatus.PENDING, include_workflow=True)
return None