How Generation Settlement Logic Works in the Awesome‑GPT‑Image‑2 Platform

The Awesome‑GPT‑Image‑2 platform handles generation settlement through a two‑phase lookup‑and‑settle workflow that reconciles pending APIMart tasks against PostgreSQL reservations using the settlePlatformGeneration helper and atomic stored procedures.

The Awesome‑GPT‑Image‑2 repository implements a provider‑agnostic architecture for AI image generation, using APIMart as the primary inference backend. When users submit generation requests, the system creates rows in the generation_reservations table that must be synchronized with external provider state. This article examines the exact mechanism—implemented across api/_lib/generation.js and api/generation/status.js—that finalizes, or "settles," these transactions once APIMart reports a terminal state.

The Two‑Phase Settlement Architecture

The generation settlement logic follows a deterministic two‑phase pattern: first verifying local reservation state, then reconciling with the external provider to ensure consistency between the APIMart task lifecycle and the platform’s internal billing records.

Phase 1: Local Reservation Lookup and Short‑Circuiting

When a client polls for status via GET /api/generation/status, the handler immediately invokes findPlatformGeneration (lines 48‑57 in api/_lib/generation.js) to query the generation_reservations table, filtering by provider='apimart' and the APIMart task ID. If the reservation already carries a final status—either succeeded or failed—the system calls formatStoredGeneration (lines 29‑45) to convert the database row into a JSON response and returns it immediately, avoiding unnecessary external API calls.

Phase 2: External Provider Reconciliation

For reservations still marked pending, the handler proceeds to fetch the latest task state from APIMart using getApimartTask (lines 56‑63 in api/generation/status.js). When this call returns a terminal state—completed or failed—the trigger is pulled for settlement.

Core Settlement Implementation

The heart of the logic resides in settlePlatformGeneration, an async function exported from api/_lib/generation.js that performs three critical operations: updating provider‑specific metadata, persisting the final cost and result URL, and invoking PostgreSQL stored procedures to handle side effects.

Updating Provider Metadata

First, settlePlatformGeneration extracts cost and result metadata via providerFieldsForTask (lines 18‑27), which returns an object containing provider_cost_usd, provider_result_url, and provider_result_expires_at. The function then executes an .update() query against generation_reservations, constrained by .eq('status', 'pending') to prevent race conditions.

Atomic Completion via Stored Procedures

To ensure ACID compliance for billing and quota management, the platform delegates state transitions to PostgreSQL stored procedures defined in supabase/migrations/20260828090000_apimart_generation_tasks.sql:

  • Successful completions: When task.status === 'completed' and an image exists, the handler calls complete_generation_reservation (via client.rpc at lines 71‑77), passing the reservation ID. This stored procedure marks the reservation as finished and triggers downstream bookkeeping such as user quota debiting.
  • Failure handling: For failed tasks, the system invokes release_generation_reservation (lines 79‑84), optionally passing the APIMart error code to annotate the failure reason in the database.

Practical Code Examples

Querying Generation Status (Client Side)

// Call the status endpoint with a known APIMart task ID
async function getGenerationStatus(taskId) {
  const resp = await fetch(`/api/generation/status?taskId=${encodeURIComponent(taskId)}`);
  const data = await resp.json();
  if (!data.ok) throw new Error(data.error);
  return data; // contains {status, image, cost, ...}
}

Server‑Side Status Handler (Simplified)

// Inside api/generation/status.js
const reservation = await findPlatformGeneration(client, taskId, userId);
if (!reservation) return notFound();

const stored = formatStoredGeneration(reservation);
if (stored) return stored; // already settled

const task = await getApimartTask({ apiKey, taskId });
if (['completed', 'failed'].includes(task.status)) {
  await settlePlatformGeneration(client, reservation, task);
}
return { ...task, user: /* user profile if finished */ };

The Settlement Helper Implementation

// Inside api/_lib/generation.js
export async function settlePlatformGeneration(client, reservation, task) {
  if (!reservation || reservation.status !== 'pending') return false;

  await client
    .from('generation_reservations')
    .update(providerFieldsForTask(task))
    .eq('id', reservation.id)
    .eq('status', 'pending');

  if (task.status === 'completed' && task.image) {
    await client.rpc('complete_generation_reservation', { p_reservation_id: reservation.id });
  } else {
    await client.rpc('release_generation_reservation', {
      p_reservation_id: reservation.id,
      p_error_code: task.errorCode || 'GENERATION_FAILED',
    });
  }
  return true;
}

Summary

  • Two‑phase architecture: The platform first checks the generation_reservations table for cached terminal states; if pending, it queries APIMart and triggers settlement only upon detecting a completed or failed task.
  • Centralized settlement logic: The settlePlatformGeneration function in api/_lib/generation.js handles all provider‑specific field extraction and database updates, ensuring idempotency via status='pending' filters.
  • Database‑driven side effects: Billing, quota updates, and reservation finalization are executed inside PostgreSQL stored procedures (complete_generation_reservation and release_generation_reservation) to guarantee atomicity.
  • Provider abstraction: The design isolates APIMart‑specific details (costs, result URLs) from the core reservation schema, allowing the settlement framework to accommodate additional providers without structural changes.

Frequently Asked Questions

What triggers the generation settlement process in Awesome‑GPT‑Image‑2?

The settlement process is triggered automatically when a client or background worker invokes the GET /api/generation/status endpoint and the system detects that the corresponding APIMart task has reached a terminal state (completed or failed). Until that moment, the reservation remains in a pending state, and repeated status calls simply return the cached pending record without side effects.

Why does the platform use PostgreSQL stored procedures instead of application‑level updates?

Stored procedures (complete_generation_reservation and release_generation_reservation) are used to guarantee atomicity for cross‑cutting concerns like user quota debiting and cost accounting. By encapsulating these side effects inside the database transaction, the system prevents partial updates if the Node.js process crashes mid‑settlement and avoids race conditions when multiple concurrent requests attempt to settle the same reservation simultaneously.

How does settlePlatformGeneration prevent duplicate settlement of the same reservation?

The function includes a guard clause that returns false if the reservation status is not pending. Additionally, the Supabase update query uses .eq('status', 'pending') as a conditional filter, ensuring that even under high concurrency, only the first caller succeeds in transitioning the row, while subsequent attempts affect zero rows and silently exit.

What specific provider data is captured during settlement?

According to the providerFieldsForTask implementation (lines 18‑27 in api/_lib/generation.js), the settlement logic extracts and persists three critical fields from the APIMart task object: provider_cost_usd (the actual inference cost), provider_result_url (the temporary CDN link to the generated image), and provider_result_expires_at (the URL expiration timestamp). These fields enable downstream cost analysis and secure image retrieval without repeated calls to the APIMart API.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →