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
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:
@@ -126,17 +126,22 @@ describe("<Dashboard /> smoke", () => {
|
||||
]);
|
||||
render(wrap(<Dashboard />, mp));
|
||||
// Wait for async discover to complete and cards to render. Dashboard
|
||||
// appends a synthetic Piper-TTS demo card to whatever the indexer
|
||||
// returned, so the count is N+1 until the on-chain TTS supplier ships.
|
||||
// appends two synthetic demo cards (Piper-TTS + Kimi K2.6 chat) to whatever
|
||||
// the indexer returned, so the count is N+2 until on-chain suppliers ship.
|
||||
await waitFor(() => {
|
||||
const cards = document.querySelectorAll("[data-testid='supplier-card']");
|
||||
expect(cards.length).toBe(3);
|
||||
expect(cards.length).toBe(4);
|
||||
});
|
||||
// Sanity: one of the cards is the demo Piper supplier.
|
||||
const piperBadges = Array.from(
|
||||
document.querySelectorAll("[data-testid='supplier-card']"),
|
||||
).filter((c) => c.textContent?.includes("audio.synthesize.piper.v1"));
|
||||
expect(piperBadges.length).toBe(1);
|
||||
// Sanity: one of the cards is the demo Kimi K2.6 chat supplier.
|
||||
const kimiBadges = Array.from(
|
||||
document.querySelectorAll("[data-testid='supplier-card']"),
|
||||
).filter((c) => c.textContent?.includes("llm.chat.v1"));
|
||||
expect(kimiBadges.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user