Skip to content

Agent Job Queue

A work queue an operator hands to the hermes bot — an external worker that authenticates as an AGENT-role user, does the work outside our process, and proposes reviewable output back. The worker side is documented in Hermes Agent Host.

This is distinct from an agent session: a session is an LLM conversation running inside the backend, a job is a unit of work executed by an outside agent.


Job types

The type column is the capability discriminator the hermes host dispatches on.

Type Input Reviewable output
product_ingest A manifest of uploaded files (object key, relative path, size, content type), each validated to live under the plain — non-temporary — ingest prefix Product drafts
guidelines_extraction A payload: entry URLs (1–10), an objective, a product cap, the aspects to extract, and optionally the shooting whose guidelines to fill. No manifest Preset / shot-type upserts

Beyond its input, a job carries: an operator note, an append-only events progress log, and — once the bot reports — a summary plus a free-form reasoning narrative describing the reading the agent applied (the naming convention it detected, how it grouped photos, its assumptions). That narrative is what lets an operator critique the reading instead of correcting each draft.


Lifecycle

stateDiagram-v2
    [*] --> QUEUED : operator creates
    QUEUED --> CLAIMED : bot claims (gets a job-scoped token)
    CLAIMED --> RUNNING : first event / heartbeat
    RUNNING --> COMPLETED : summary + reasoning
    RUNNING --> FAILED : error
    CLAIMED --> QUEUED : release (never started)
    RUNNING --> QUEUED : release (never started)
    COMPLETED --> QUEUED : revise (operator feedback)
    QUEUED --> CANCELLED : operator cancels
    COMPLETED --> [*]
  • Release hands the job back unstarted — for the case where the worker could not reach the model service at all. Reporting FAILED there would tell the operator their drop was rejected when nothing was wrong with it.
  • Revise supersedes the drop's un-reviewed drafts and re-queues the job with the operator's plain-language correction attached ("the _D photos are the back"), injected as a hard directive on the next run.
  • Stale claims can be re-claimed.

Flow

sequenceDiagram
    participant O as Operator (webapp)
    participant API as Backend API
    participant B as Hermes bot
    participant WS as WebSocket

    O->>API: create job (manifest or payload)
    B->>API: list jobs (own AGENT token, filtered by type)
    B->>API: claim job
    API-->>B: job-scoped token + presigned GET URLs
    loop while working
        B->>API: append event / heartbeat (job token)
        O->>API: poll job (status + event log)
    end
    B->>API: propose output on the capability's own surface
    API-->>WS: draft created
    B->>API: complete (summary + reasoning)
    alt operator disagrees with the reading
        O->>API: revise (feedback) → back to QUEUED
    end

API surface

Prefix /agent-jobs. Two caller populations share it.

Method + path Caller Auth
POST / operator User token, non-agent, organization-gated. A capture-session (phone) token is explicitly rejected — the phone is presign-only, and its drop becomes exactly one job through seal-on-close
GET / operator or bot User token; filter by status, type, shooting
GET /{job_id} operator User token, membership-scoped — powers the live "reading your drop" state in the webapp
POST /{job_id}/revise operator User token, non-agent
POST /{job_id}/claim bot Agent user token → returns the job-scoped token
POST /{job_id}/events, /heartbeat bot Job token
POST /{job_id}/complete, /release, /fail bot Job token

The bot lists and claims with its ordinary agent token, then switches to the job-scoped token — short-lived (30 minutes) and renewed by every heartbeat — for everything after the claim. Each job-token endpoint re-checks that the token is bound to the job in the path, so one job's token can never drive another's.