File size: 5,545 Bytes
1b2323a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# Generation foundation

MediaRouter has a provider-neutral generation domain for image and video
workers. The audited optional WAN 2.2 and FLUX.2 Klein integrations are
documented in [`generation-wan.md`](generation-wan.md) and
[`generation-flux.md`](generation-flux.md). Each remains unavailable until its
trusted worker configuration and live readiness verification succeed. Other
models remain unregistered.

## Architecture

```text
REST / MCP / SDK / n8n (future transports)
                 |
         GenerationService
                 |
  GenerationProviderRegistry (verified adapters only)
                 |
 GenerationRepository + authoritative tenancy + RLS
                 |
       CanonicalMediaAsset references
```

`GenerationService` is the single transport-neutral orchestration boundary.
Provider adapters must supply strict typed validation and worker submission;
transports must not accept arbitrary provider payloads or worker URLs.

## Data and tenancy

The security database migration
[`0003_generation_domain_postgres.sql`](../app/security/migrations/0003_generation_domain_postgres.sql)
adds these workspace-scoped tables:

- `generation_requests`: immutable validated intent and its idempotency
  fingerprint.
- `generation_jobs`: exactly one durable logical execution per request.
- `generation_job_attempts`: retry audit history, without creating a new job.

Input and output media are opaque IDs referencing `media_assets`. Client paths,
local paths, direct object-store URLs, and provider credentials are never
accepted or returned. Database triggers ensure request input assets and job
outputs belong to the same workspace as the request/job. PostgreSQL RLS uses
the already-established `app.workspace_id` and `app.user_id` session context.
[`0004_generation_provider_runtime_postgres.sql`](../app/security/migrations/0004_generation_provider_runtime_postgres.sql)
adds a unique provider/external-job binding so a remote worker identity cannot
be attached to jobs in more than one workspace.

## API

All endpoints require MediaRouter authentication and an authoritative active
workspace membership.

| Method | Endpoint | Scope | Purpose |
|---|---|---|---|
| `GET` | `/v1/generation/providers` | `generation:providers:read` | Capability discovery; no unavailable provider is advertised as usable. |
| `GET` | `/v1/generation/providers/{provider}` | `generation:providers:read` | One provider's public capabilities. |
| `GET` | `/v1/generation/models` | `generation:providers:read` | Server-owned model discovery; availability requires verified worker readiness. |
| `GET` | `/v1/generation/providers/{provider}/models/{model_id}` | `generation:providers:read` | One registered provider model. |
| `POST` | `/v1/generation/requests` | `generation:requests:create` | Create a durable job once an available adapter exists. Requires `Idempotency-Key`. |
| `GET` | `/v1/generation/requests` | `generation:requests:read` | List only caller-workspace requests. |
| `GET` | `/v1/generation/requests/{id}` | `generation:requests:read` | Read one caller-workspace request and job. |
| `GET` | `/v1/generation/jobs/{id}` | `generation:requests:read` | Read one caller-workspace job. |
| `POST` | `/v1/generation/jobs/{id}/cancel` | `generation:jobs:cancel` | Cancel queued work or request cancellation for active work. |

The strict foundation request envelope is:

```json
{
  "provider": "future-provider",
  "model_id": "verified-model-id",
  "modality": "image",
  "prompt": "A production-safe prompt",
  "input_asset_id": "optional-canonical-media-asset-uuid"
}
```

Unknown JSON fields are rejected. Provider-specific controls are deliberately
not accepted unless the relevant adapter supplies a reviewed typed schema. WAN
uses the closed `wan` schema documented in
[`generation-wan.md`](generation-wan.md); FLUX uses the closed `flux` schema
documented in [`generation-flux.md`](generation-flux.md).

## Job semantics

The state machine is `queued → submitting → running → succeeded`, with
`retrying`, `failed`, `cancel_requested`, and `cancelled` paths. A retry
continues the original `generation_jobs` row; it never creates another logical
generation. Queued jobs cancel immediately. Active jobs become
`cancel_requested` until the configured provider confirms cancellation, so the API
does not make a false cancellation claim.

An `Idempotency-Key` is required for every submission. The database enforces
one key per workspace; MediaRouter fingerprints the normalized request and
returns `GENERATION_IDEMPOTENCY_CONFLICT` when a caller reuses a key with a
different payload.

## Deployment

For local SQLite development, metadata is created with the rest of the
security schema. PostgreSQL deployments must apply all security migrations in
order, including `0003_generation_domain_postgres.sql` and
`0004_generation_provider_runtime_postgres.sql`, before startup.

Relevant configuration:

```env
GENERATION_ENABLED=true
GENERATION_JOB_RETRY_LIMIT=3
AI_WORKER_CONNECT_TIMEOUT_SECONDS=10
AI_WORKER_REQUEST_TIMEOUT_SECONDS=60
AI_WORKER_READ_TIMEOUT_SECONDS=300
AI_WORKER_MAX_RETRIES=3
AI_WORKER_RETRY_BACKOFF_SECONDS=0.5
```

These settings provide shared worker transport defaults only. Provider URLs
and tokens stay backend-only and are documented with each verified provider.

The provider-runtime contract, worker transport, output handoff, and future
adapter requirements are documented in
[`generation-providers.md`](generation-providers.md). WAN and FLUX have
separately reviewed optional adapters.