feat: llm.chat.v1 multi-turn supplier type + free Kimi K2.6 chat demo
Some checks failed
CI / typecheck + vitest (Node 20) (push) Has been cancelled

Adds a conversational supplier capability and a free demo, both streaming.

New paid `llm.chat.v1` type: one escrow per conversation (flat fee). "Start
chat" posts the escrow with a session-init placeholder prompt_hash and the
supplier Claims (reserving its single slot); turns then stream off-chain via
SSE with zero chain interaction; "End chat" has the supplier Submit a receipt
over the full transcript and the buyer Accept — the moment the user is charged.
The on-chain validator is content-agnostic (pins but never verifies the
hashes), so this reuses the existing contract unchanged. A supplier-side idle
watchdog auto-ends abandoned sessions before deliver_by.

Free Kimi K2.6 chat demo: a synthetic "demo:kimi-chat" tile that uses the same
chat UI but proxies straight to OpenRouter (no escrow, no payment), mirroring
the existing Piper demo.

Shared:
- postChatEscrow.ts + chatSessionPromptHash() (session-init prompt_hash helper
  shared by the buyer builder and the supplier start gate).

Supplier:
- CAPABILITY_KIND="chat-session" (+ CHAT_IDLE_TIMEOUT_MS); callOpenAiStream()
  streaming client; ChatSessionStore + endChatSession(); /v1/chat/{start,
  message,end} handlers with idle + hard-cap watchdog timers.

Buyer:
- Marketplace.startChat()/endChat() with relaxed (session-init) receipt
  verification + crypto verifyReceipt; /v1/chat/{start,message,end} routes
  (SSE passthrough) and a free /v1/chat-demo/message OpenRouter proxy;
  OPENROUTER_API_KEY/OPENROUTER_BASE_URL config; ChatForm.tsx + Dashboard
  KIMI_DEMO_SUPPLIER tile and llm.chat.v1 dispatch.

Deploy:
- docker-compose.supplier-kimi-chat.yml + supplier/.env.kimi-chat.example.

Typecheck passes across all workspaces; full vitest suite green except 15
pre-existing time-bomb/RED failures (tx-claim/accept/post-advert live-CBOR
fixtures with hardcoded past deadlines + the M0-C golden-datum test), confirmed
identical on a clean tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
david
2026-06-08 16:18:54 +02:00
parent e01a03b7f2
commit 9acad5b2b8
17 changed files with 1997 additions and 13 deletions

View File

@@ -0,0 +1,62 @@
# supplier/.env.kimi-chat.example
#
# Env for the MAINNET Kimi K2.6 MULTI-TURN CHAT supplier (capability
# `llm.chat.v1`, CAPABILITY_KIND=chat-session). Copy to supplier/.env.kimi-chat
# on the host (chmod 600) and fill in real values. .env.kimi-chat is gitignored.
#
# This is a SEPARATE wallet/advert from supplier/.env.kimi (the one-off Kimi
# supplier) — the chat session holds the single-slot lock for the whole
# conversation, so it runs as its own process.
# ─── Required ─────────────────────────────────────────────────────────────
# 64-char hex Ed25519 private key seed for THIS supplier's wallet. SECRET.
SUPPLIER_PRIV_KEY_HEX=PASTE_64_HEX_CHARS_HERE
# OpenRouter API key (Bearer). SECRET.
OPENAI_API_KEY=PASTE_OPENROUTER_KEY_HERE
# Ogmios WebSocket URL (mainnet).
OGMIOS_URL=wss://ogmios.vector.mainnet.apexfusion.org
# OutputReference of this supplier's on-chain `llm.chat.v1` advert UTxO.
# Post it first (see tx:post-advert below), then paste "<txHash>#0" here.
ADVERT_REF=PASTE_TXHASH_HERE#0
# Mainnet.
NETWORK_ID=1
# Enable real chain submit/await (Claim + Submit).
LIVE_CHAIN=1
# ─── Backend (chat-session is openai-only) ────────────────────────────────
# CAPABILITY_KIND, LLM_BACKEND, OPENAI_BASE_URL, OPENAI_TIMEOUT_MS, and
# CHAT_IDLE_TIMEOUT_MS are pinned in docker-compose.supplier-kimi-chat.yml.
# Override CHAT_IDLE_TIMEOUT_MS here only if you want a different idle window.
# ─── tx:post-advert — run once before first deploy ────────────────────────
# Post an llm.chat.v1 advert with a LARGE max-processing-ms so Claim (start)
# and Submit (end) both land before deliver_by:
# pnpm --filter @marketplace/supplier tx:post-advert \
# --capability-id llm.chat.v1 \
# --model moonshotai/kimi-k2.6 \
# --max-output-tokens 4096 \
# --max-processing-ms 1800000 \
# --price-lovelace 2000000 \
# --endpoint-url https://mp-suppliers-kimi-chat.vector.apexfusion.org
# Copy the printed "<txHash>#0" into ADVERT_REF above.
ADVERT_CAPABILITY_ID=llm.chat.v1
ADVERT_MODEL=moonshotai/kimi-k2.6
ADVERT_MAX_OUTPUT_TOKENS=4096
ADVERT_MAX_PROCESSING_MS=1800000
ADVERT_PRICE_LOVELACE=2000000
ADVERT_SUPPLIER_BOND_LOVELACE=1000000
ADVERT_BUYER_BOND_LOVELACE=1000000
ADVERT_ENDPOINT_URL=https://mp-suppliers-kimi-chat.vector.apexfusion.org
ADVERT_DETAIL_URI=
ADVERT_DETAIL_HASH=
# ─── CIP-33 reference scripts (recommended on mainnet) ────────────────────
# ESCROW_REF_UTXO=<txhash>#0
# ADVERT_REF_UTXO=<txhash>#1
# VECTOR_ZERO_TIME_MS=<epoch-ms>