MVP demo: one operator-funded API key anyone can plug into an IDE/harness,
running real escrow-per-session marketplace conversations (llm.chat.v1)
behind the standard OpenAI /chat/completions wire shape.
- shared: ChatMessage gains tool role + tool_calls; normalizeChatMessage/
chatMessagesEquivalent keep supplier transcript and gateway mirror
hash-identical for receipts (field presence is part of the identity)
- supplier: /v1/chat/message accepts {messages,tools,tool_choice} alongside
legacy {content}; callOpenAiStream forwards tools, accumulates fragmented
delta.tool_calls, allows content-less tool turns; done frame carries the
assistant message verbatim + finish_reason + usage
- gateway: demo flag on api_keys (additive migration), create-demo-key CLI,
withdraw 403 + hidden deposit address for demo keys, per-IP demo rate
limit (demo keys skip the shared per-key limit), models filtered to chat
capability
- gateway executor (demoChat.ts): transcript-prefix affinity maps stateless
calls onto open sessions, forwards only unseen deltas, transparently
reopens on supplier idle-close; never falls back to one-shot (its settle
path assumes <=1 in-flight escrow per wallet)
- mutex scope: key mutex held only for chain work (open/close); off-chain
turns serialize on per-session locks so replicas serve users concurrently
- sweeper: chat-aware reclaim guard (35min vs 11min) and abandoned-session
cleanup; terminal state confirmed via on-chain queryUtxo (indexer keeps
lineage rows at their old state forever)
- deploy: kimi-chat replicas 2+3 compose files; chat idle timeout 2.5min
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
77 lines
3.1 KiB
YAML
77 lines
3.1 KiB
YAML
# deploy/mainnet/docker-compose.supplier-kimi-chat-2.yml — Supplier — MAINNET
|
|
# (OpenRouter / Kimi K2.6 — MULTI-TURN CHAT capability `llm.chat.v1`, REPLICA 2)
|
|
#
|
|
# Second llm.chat.v1 replica: a chat session holds a supplier's single slot for
|
|
# the whole conversation, so concurrent chat users = number of chat suppliers.
|
|
# Deployed for the shared-demo-key endpoint (session-backed /chat/completions).
|
|
# Identical to docker-compose.supplier-kimi-chat.yml except for its own wallet,
|
|
# advert, env file and hostname.
|
|
#
|
|
# Pre-flight:
|
|
# 1. DNS A-record: mp-suppliers-kimi-chat-2.vector.apexfusion.org → host IP
|
|
# 2. New supplier wallet (gen-keypair), funded with advert bond + fee float.
|
|
# 3. Post a fresh llm.chat.v1 advert for this wallet:
|
|
# --capability-id llm.chat.v1 --model moonshotai/kimi-k2.6
|
|
# --max-processing-ms 1800000 (same price as the primary chat advert)
|
|
# 4. supplier/.env.kimi-chat-2 written on host (chmod 600) with at minimum:
|
|
# SUPPLIER_PRIV_KEY_HEX, OPENAI_API_KEY, OGMIOS_URL, NETWORK_ID=1,
|
|
# VECTOR_ZERO_TIME_MS, ESCROW_REF_UTXO, ADVERT_REF_UTXO, ADVERT_REF,
|
|
# LIVE_CHAIN=1
|
|
|
|
name: marketplace-mainnet-supplier-kimi-chat-2
|
|
|
|
services:
|
|
supplier:
|
|
build:
|
|
context: ../..
|
|
dockerfile: supplier/Dockerfile
|
|
container_name: marketplace-mainnet-supplier-kimi-chat-2
|
|
restart: unless-stopped
|
|
env_file:
|
|
- path: ../../supplier/.env.kimi-chat-2
|
|
required: false
|
|
environment:
|
|
# Multi-turn chat session capability (mounts /v1/chat/{start,message,end}).
|
|
CAPABILITY_KIND: chat-session
|
|
LLM_BACKEND: openai
|
|
# No /v1 suffix — supplier/src/openai.ts appends /v1/chat/completions.
|
|
OPENAI_BASE_URL: https://openrouter.ai/api
|
|
# Kimi K2.6 generations can be slow; mirror the one-off Kimi compose.
|
|
OPENAI_TIMEOUT_MS: "300000"
|
|
# 2.5 min idle end: single-slot suppliers must free up quickly for the
|
|
# shared demo endpoint (the gateway transparently reopens on next turn).
|
|
CHAT_IDLE_TIMEOUT_MS: "150000"
|
|
PORT: "8080"
|
|
# Enable LiveOgmiosProvider so Claim/Submit actually broadcast.
|
|
LIVE_CHAIN: "1"
|
|
# NETWORK_ID and OGMIOS_URL intentionally not pinned here — they MUST
|
|
# come from the operator-provided supplier/.env.kimi-chat-2 on a mainnet host.
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/healthz >/dev/null || exit 1"]
|
|
interval: 20s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 15s
|
|
networks:
|
|
- marketplace-mainnet-net
|
|
- traefik-net
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network=traefik-net"
|
|
- "traefik.http.routers.mp-suppliers-kimi-chat-2-mainnet.entrypoints=web"
|
|
- "traefik.http.routers.mp-suppliers-kimi-chat-2-mainnet.rule=Host(`mp-suppliers-kimi-chat-2.vector.apexfusion.org`)"
|
|
- "traefik.http.services.mp-suppliers-kimi-chat-2-mainnet.loadbalancer.server.port=8080"
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
networks:
|
|
marketplace-mainnet-net:
|
|
external: true
|
|
name: marketplace-mainnet-net
|
|
traefik-net:
|
|
external: true
|
|
name: traefik-net
|