Files
agents-marketplace/packages/shared
jelisaveta-talbot 34a52d5d16 buyer: TTS marketplace lifecycle (audio.synthesize.piper.v1)
Path-A buyer side: PostEscrow → supplier /v1/audio/synthesize → 202+poll
→ on-chain Submit → receipt verify, returning the audio bytes + signed
receipt to the SPA. Pairs with the supplier-side scaffolding in 3c3e009.

Files

- packages/shared/src/tx/escrow/postTtsEscrow.ts (new):
  buildPostTtsEscrowTx() mirrors postEscrow.ts but commits a TTS-shaped
  prompt_hash = sha256(canonical({text, voice, format, speed})). The
  same hash is exposed as ttsPromptHash() so the buyer SDK and supplier
  validation can pin the canonicalisation; any drift fails the
  supplier's prompt_mismatch gate. Validates body shape (text non-empty,
  voice/format in allow-list, speed ∈ [0.5,1.5]); reuses the chat live-
  cbor path which is already capability-agnostic.

- packages/shared/src/tx/index.ts: export the new TTS surface.

- buyer/src/sdk/Marketplace.ts: + submitTts() — full lifecycle mirror of
  submitPrompt with TTS-shaped POST body, /v1/audio/synthesize endpoint,
  and audio_b64 in the polled response. Receipt verification gates on
  prompt_hash via ttsPromptHash() instead of canonicalize(messages).

- buyer/src/sdk/types.ts: + SubmitTtsOptions / SubmitTtsResult.

- buyer/src/server.ts: + POST /v1/submit-tts (mirrors /v1/submit-prompt
  shape; routes to marketplace.submitTts).

- buyer/src/ui/components/PiperTTSForm.tsx: two-mode rendering. When
  advertRef + payment_lovelace are passed, posts to /v1/submit-tts and
  decodes base64 audio into a blob URL. When neither is passed, falls
  back to /v1/synth-speech (the path-B direct demo proxy).

- buyer/src/ui/pages/Dashboard.tsx: capability dispatch routes a real
  on-chain TTS supplier to the marketplace mode and the synthetic demo
  card to the direct mode (its utxo_ref="demo:piper-tts" fails the ref
  parser → advertRef is null → demo mode). Same component for both.

Tests still passing: 31 buyer + 29 supplier; both typechecks clean.
Chat path behaviourally untouched.
2026-05-06 22:00:31 +02:00
..