Skip to content

Repository files navigation

Quinn

Quinn is a thin TypeScript A2A gateway built on samsar-js for Samsar text-to-video generation. It gives agents an account-scoped workflow to create a billing account, purchase credits, submit a prompt and duration, monitor the render, and retrieve the completed video URL.

Quinn fixes the generation pipeline to Qwen 3.7, Wan 2.7 Pro, and Happy Horse 1.1. It omits every other generation setting so Samsar can apply its defaults.

Features

  • Creates isolated Samsar external-user accounts and returns a scoped account key.
  • Creates credit checkout sessions and exposes account-specific payment status and balances.
  • Accepts text-to-video requests through A2A 1.0 JSON-RPC or HTTP+JSON.
  • Polls and lists account-owned render tasks and returns completed video URLs as A2A artifacts.
  • Prevents callers from changing Quinn's fixed model pipeline; additional generation settings are ignored and not forwarded.
  • Keeps no local account, billing, or task database; Samsar remains the system of record.

Architecture

flowchart LR
    Agent["A2A agent"] -->|"Create account, fund, submit, poll"| Quinn["Quinn"]
    Quinn -->|"Platform key for provisioning"| Samsar["Samsar API"]
    Quinn -->|"Scoped external-user key"| Samsar
    Samsar --> Pipeline["Fixed Quinn video pipeline"]
    Pipeline -->|"Task status and video URL"| Quinn
    Quinn --> Agent
Loading

Quinn holds one Samsar platform API key on the server. POST /accounts provisions a high-entropy external-user identity and returns its scoped account key. Billing, generation, status, and task-list operations use that scoped key, keeping credits and renders isolated to the agent's account.

The account key is the account credential. Quinn does not persist it or provide a recovery endpoint, so clients must store it securely when it is returned.

Fixed video pipeline

Stage Model key Model
Inference QWEN3.7 Qwen 3.7
Text to image WAN2.7PRO Wan 2.7 Pro
Image to video HAPPYHORSEI2V Happy Horse 1.1 I2V

For text-to-video generation, the generation input contains exactly these five fields:

{
  "prompt": "A cinematic launch film for an electric motorcycle at night",
  "duration": 10,
  "inference_model": "QWEN3.7",
  "image_model": "WAN2.7PRO",
  "video_model": "HAPPYHORSEI2V"
}

Callers control only prompt and duration. All other generation fields are omitted and use Samsar defaults.

Installation

Requirements

  • Git
  • Node.js 20 or newer with npm
  • A Samsar platform API key

Clone and install Quinn:

git clone https://github.com/samsarone/Quinn.git
cd Quinn
npm ci
cp .env.example .env

Add the platform credential to .env:

SAMSAR_API_KEY=your-platform-api-key
PUBLIC_BASE_URL=http://localhost:8080

Start the development server:

npm run dev

Quinn listens on http://localhost:8080 by default. Confirm it is running:

curl -sS http://localhost:8080/health

Quick start

1. Create an account

Account creation is outside A2A because the returned credential authenticates the agent's later A2A and billing requests.

curl -sS -X POST http://localhost:8080/accounts \
  -H 'content-type: application/json' \
  -d '{
    "display_name": "Launch Video Agent",
    "external_agent_id": "agent-123",
    "metadata": { "team": "creative" }
  }'

The response includes the new account and its credential. This is an abbreviated example: Quinn generates the account ID at runtime, while Samsar supplies the scoped credential and account data.

{
  "account": {
    "id": "<account-id>",
    "provider": "quinn"
  },
  "credentials": {
    "accountKey": "<account-key>",
    "authorization": "Bearer <account-key>",
    "headerName": "x-quinn-account-key"
  }
}

Store the returned key for the remaining examples:

export QUINN_ACCOUNT_KEY="<account-key>"

Caller-supplied external IDs can provide attribution, but none controls Quinn's generated account identity or ownership boundary.

2. Purchase credits

Create a checkout for a positive integer number of credits:

curl -sS -X POST http://localhost:8080/billing/credits/purchases \
  -H "Authorization: Bearer $QUINN_ACCOUNT_KEY" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: purchase-500-credits-1' \
  -d '{ "credits": 500 }'

Open the returned url to complete checkout, then poll with an externalPaymentId, checkoutSessionId, paymentIntentId, or setupIntentId returned by Samsar:

curl -sS 'http://localhost:8080/billing/payments/status?checkoutSessionId=<checkout-session-id>' \
  -H "Authorization: Bearer $QUINN_ACCOUNT_KEY"

Payment state progresses from pending to succeeded or failed. Credits are applied upstream after payment succeeds.

Check the account balance:

curl -sS http://localhost:8080/billing/credits \
  -H "Authorization: Bearer $QUINN_ACCOUNT_KEY"

3. Submit text to video

Send an A2A 1.0 JSON-RPC request with a prompt and duration. Prompts may contain up to 4,000 characters; duration must be from 10 through 240 seconds.

curl -sS -X POST http://localhost:8080/a2a \
  -H "Authorization: Bearer $QUINN_ACCOUNT_KEY" \
  -H 'A2A-Version: 1.0' \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": "submit-1",
    "method": "SendMessage",
    "params": {
      "configuration": { "returnImmediately": true },
      "metadata": { "skill": "text_to_video" },
      "message": {
        "role": "ROLE_USER",
        "messageId": "launch-film-1",
        "parts": [{
          "data": {
            "input": {
              "prompt": "A cinematic launch film for an electric motorcycle at night",
              "duration": 10
            }
          }
        }]
      }
    }
  }'

Save result.task.id from the response. messageId is required, may contain at most 200 characters and no control characters, and is also forwarded as the Samsar idempotency key.

returnImmediately: true returns the submitted task for polling. If omitted or set to false, Quinn follows A2A's blocking behavior and polls until the task reaches a returnable state or A2A_BLOCKING_WAIT_TIMEOUT_MS expires.

4. Poll the task

curl -sS -X POST http://localhost:8080/a2a \
  -H "Authorization: Bearer $QUINN_ACCOUNT_KEY" \
  -H 'A2A-Version: 1.0' \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": "poll-1",
    "method": "GetTask",
    "params": { "id": "<task-id>" }
  }'

Continue polling while the task is TASK_STATE_SUBMITTED or TASK_STATE_WORKING. Stop on TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_CANCELED, or TASK_STATE_REJECTED; handle TASK_STATE_INPUT_REQUIRED, TASK_STATE_AUTH_REQUIRED, and TASK_STATE_UNSPECIFIED explicitly. Every task includes a samsar-response artifact with the raw status payload. When Samsar returns an output URL, a completed task also includes a result-video artifact with one or more video/mp4 URL parts.

The equivalent HTTP+JSON request is:

curl -sS 'http://localhost:8080/tasks/<task-id>' \
  -H "Authorization: Bearer $QUINN_ACCOUNT_KEY" \
  -H 'A2A-Version: 1.0'

A2A interface

The public Agent Card is served at /.well-known/agent-card.json. Authenticated operations accept either Authorization: Bearer <account-key> or x-quinn-account-key: <account-key>.

Send A2A-Version: 1.0 on every A2A operation. A missing version header is interpreted as A2A 0.3 and rejected because Quinn exposes only version 1.0.

Operations

Operation JSON-RPC method HTTP+JSON Behavior
Send message SendMessage POST /message:send Runs a Quinn skill and returns a message or task.
Get task GetTask GET /tasks/:id Gets current render state and artifacts.
List tasks ListTasks GET /tasks Lists recent tasks owned by the account.
Cancel task CancelTask POST /tasks/:id:cancel Returns TaskNotCancelable; external T2V cancellation is not available upstream.

Follow-up messages containing an existing taskId, streaming, push notifications, task subscription, and extended Agent Cards are not supported. Use a new SendMessage request to create work and GetTask to poll it.

Skills

Skill Input Result
text_to_video prompt, duration Starts a render and returns an A2A task.
get_credits none Returns the current account balance in an A2A message.
purchase_credits positive integer credits Returns checkout details in an A2A message.
get_payment_status A payment or checkout identifier Returns the account-scoped payment status in an A2A message.

Atlas-compatible aliases are accepted, including create_video_from_text, create_credits_recharge, and billing_get_payment_status.

HTTP API

Method Endpoint Auth Purpose
GET / none Service metadata and primary links.
GET /health none Liveness check.
GET /.well-known/agent-card.json none A2A discovery.
POST /accounts none Creates an external-user account and scoped credential.
GET /billing/credits account key Gets the current credit balance.
POST /billing/credits/purchases account key Creates a credit checkout.
GET /billing/payments/status account key Gets checkout or payment status.
POST /a2a account key A2A 1.0 JSON-RPC endpoint.
POST /message:send account key A2A HTTP+JSON Send Message.
GET /tasks/:id account key A2A HTTP+JSON Get Task.
GET /tasks account key Lists recent account-owned T2V tasks.
POST /tasks/:id:cancel account key Reports that the task cannot be canceled.

Account, billing, and authenticated A2A operation responses use Cache-Control: no-store. The public Agent Card is cached for five minutes. Account creation and credit checkout endpoints also have configurable per-IP rate limits.

Configuration

Variable Required Default Purpose
SAMSAR_API_KEY yes Server-side Samsar platform credential.
SAMSAR_API_BASE_URL no https://api.samsar.one/v1 Samsar SDK base URL; root and /v2 URLs are normalized to /v1.
PUBLIC_BASE_URL production http://localhost:$PORT Public origin advertised by the Agent Card.
PORT no 8080 HTTP listening port.
SAMSAR_REQUEST_TIMEOUT_MS no 60000 Upstream request timeout in milliseconds.
A2A_POLL_INTERVAL_MS no 2000 Poll interval for blocking SendMessage requests.
A2A_BLOCKING_WAIT_TIMEOUT_MS no 900000 Maximum blocking A2A wait in milliseconds.
JSON_BODY_LIMIT no 1mb Maximum accepted JSON body size.
RATE_LIMIT_WINDOW_MS no 900000 Window used by self-service rate limits.
ACCOUNT_CREATION_RATE_LIMIT_MAX no 10 Account creations allowed per client IP and window.
CREDIT_PURCHASE_RATE_LIMIT_MAX no 20 Checkout creations allowed per client IP and window.
TRUST_PROXY_HOPS no 0 Exact number of trusted reverse-proxy hops.
QUINN_ACCOUNT_PROVIDER no quinn Samsar external-user provider namespace.
AGENT_CARD_DOCUMENTATION_URL no omitted Public documentation URL placed in the Agent Card.

Docker

Build and run the production image:

docker build -t quinn .
docker run --rm -p 8080:8080 \
  -e SAMSAR_API_KEY="$SAMSAR_API_KEY" \
  -e PUBLIC_BASE_URL="https://quinn.example.com" \
  quinn

The runtime image uses Node.js 20 and runs as the unprivileged node user.

Development

Command Purpose
npm run dev Starts Quinn in watch mode using .env.
npm run typecheck Type-checks source and tests.
npm test Runs the Node test suite.
npm run build Compiles production output to dist/.
npm run check Runs type-checking, tests, and the production build.
npm start Starts the compiled server from dist/.

Before submitting a change:

npm run check

Security and operations

  • Keep SAMSAR_API_KEY, Quinn account keys, .env, and checkout identifiers out of source control, browser bundles, logs, and Agent Cards.
  • Serve Quinn over HTTPS in production.
  • Persist the account key in a secure secret store when POST /accounts returns it.
  • For an A2A render, use one messageId per logical operation and reuse it when retrying that operation.
  • For an HTTP credit checkout, use one Idempotency-Key per logical operation and reuse it when retrying that operation.
  • Set TRUST_PROXY_HOPS to the exact proxy count; do not enable broad proxy trust.
  • Quinn's built-in limits are per process. Multi-instance deployments should add shared account/IP quotas at the API gateway.

Documentation

Resource Link
Samsar API documentation docs.samsar.one
Samsar V2 API docs.samsar.one/v2
External-user accounts docs.samsar.one/external-users
Credits and billing docs.samsar.one/credits
A2A 1.0 specification a2a-protocol.org
A2A normative protobuf a2aproject/A2A

License

Quinn is available under the MIT License.

About

A2A connector for Alibaba Cloud models.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages