Two structural fixes for demo concurrency (3 single-slot suppliers thrashed
under Open WebUI's ~3 conversations per message):
Multi-slot suppliers (MAX_CHAT_SESSIONS, default 1):
- SupplierState is now capacity-aware: a Set of active escrow refs with
free-until-full status semantics, ref-scoped release(ref) (also fixes the
latent bug where handler catch-alls released another request's slot), and
a walletMutex serializing every wallet-spending chain op — Claim, Submit,
and wallet-health consolidation queue instead of racing the single
working/collateral UTxO. /status gains active_sessions/max_sessions.
Entry-ticket settle mode (CHAT_SETTLE_MODE=ticket, default full, both sides):
- The buyer's escrow post at session open is the ONLY chain op. The supplier
verifies the Open escrow as an entry ticket but never Claims/Submits
(/v1/chat/start → {status:"ticket"}; /v1/chat/end → receipt-less
{status:"ended"}); no hard-cap timer, so sessions may outlive deliver_by.
Used tickets can't reopen sessions (records retained; 409 session_exists).
- Buyer SDK: startChat/endChat are settle-mode aware, driven by the
supplier's response — mixed-mode rollout windows settle correctly.
- Gateway: ticket closes bill cost 0; the sweeper Reclaims Open tickets
after deliver_by WITHOUT closing live sessions (the conversation and its
affinity mirror survive their reclaimed ticket), gates reclaims on
deliver_by, and keeps an in-process settled-refs memory so terminal
indexer rows aren't retried every sweep forever.
Deployment (kimi-chat trio + gateway): ticket mode, 8 slots per supplier,
idle policy gateway 10 min / supplier 15 min (fixes the inversion where the
supplier idle-closed before the gateway janitor).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
37 lines
1.4 KiB
Plaintext
37 lines
1.4 KiB
Plaintext
# gateway/.env.example — copy to .env and fill in.
|
|
|
|
# 32-byte (64 hex char) master key used to AES-256-GCM-encrypt every user's
|
|
# custodial wallet private key at rest. Generate with: openssl rand -hex 32
|
|
# LOSING THIS PERMANENTLY LOCKS ALL USER FUNDS. Back it up out-of-band.
|
|
GATEWAY_MASTER_KEY=
|
|
|
|
# Internal indexer base URL (e.g. http://marketplace-indexer:8090).
|
|
INDEXER_URL=
|
|
|
|
# Ogmios HTTP endpoint. Required (the gateway posts/settles escrows on chain).
|
|
OGMIOS_URL=
|
|
|
|
# Must be "1" — the gateway signs and submits real transactions.
|
|
LIVE_CHAIN=1
|
|
|
|
# "0" testnet (addr_test…), "1" mainnet (addr…). Default "0".
|
|
NETWORK_ID=0
|
|
|
|
# HTTP port. Default 3010.
|
|
GATEWAY_PORT=3010
|
|
|
|
# Directory holding gateway.db (custodial keys + usage + sessions). BACK IT UP.
|
|
# Default ./data/gateway
|
|
GATEWAY_DB_DIR=./data/gateway
|
|
|
|
# Optional tuning (defaults shown):
|
|
# SIGNUP_RATE_MAX=5 # signups per IP per window
|
|
# SIGNUP_RATE_WINDOW_MS=3600000
|
|
# KEY_RATE_MAX=60 # requests per API key per window
|
|
# KEY_RATE_WINDOW_MS=60000
|
|
# SWEEPER_INTERVAL_MS=60000
|
|
# DEMO_SESSION_IDLE_MS=180000 # close demo chat sessions idle this long (frees the supplier slot)
|
|
# CHAT_SETTLE_MODE=full # "full" (Claim/Submit/Accept) or "ticket" (escrow post only; sweeper reclaims) — must match suppliers
|
|
# WALLET_HEALTH_INTERVAL_MS=600000
|
|
# SDK_REGISTRY_MAX=500 # max cached per-key Marketplace instances
|