Skip to main content
Without context, your customer support chat has to ask what the user was doing and what went wrong. With Autoplay wired in, Inkeep already knows β€” and can explain the real blocker, point to the right next step, and link directly to the relevant workflow instead of giving a generic answer. This tutorial shows you how to build that flow using the Inkeep agents framework and InkeepEmbeddedChat from @inkeep/agents-ui. Your events, conversation history, and LLM keys never leave your infrastructure. Who this is for: Teams using or evaluating Inkeep who want chat to react to what users actually do β€” not just answer generic questions. Assumes comfort with Python, TypeScript/React, and a small FastAPI service. Stack: Inkeep agents framework (Docker), @inkeep/agents-ui, Next.js 14, Python 3.10+, FastAPI, uv, and Anthropic or OpenAI. https://developers.autoplay.ai/recipes/inkeep

✨ Final result

Admin: why can't I unblock this vendor?

Bot: Vendors may be blocked for several reasons, including policy
violations, expired approvals, or missing compliance information.
Check the vendor details page for more information.

(Generic reply β€” the bot doesn't know which vendor the admin is viewing
or that the unblock attempt just failed.)
Video walkthrough β€” Open on Loom if the player does not load.

πŸ“‹ Prerequisites

Before you start, you need:
  • Node.js 18+ and Python 3.10+ on the host.
  • uv β€” the Python package manager used in this tutorial.
    curl -LsSf https://astral.sh/uv/install.sh | sh
    
  • pnpm β€” the Inkeep agents monorepo uses pnpm workspaces.
    npm i -g pnpm
    
  • Docker Desktop β€” for running Inkeep’s backing services (PostgreSQL, Doltgres, SpiceDB).
  • An Anthropic or OpenAI API key β€” the Inkeep agents framework calls your LLM directly; no Inkeep cloud key required.
That’s it. The tutorial covers every code file step by step β€” copy-paste runnable.
The Inkeep CDN widget (@inkeep/cxkit-js) requires a paid Inkeep cloud API key. This tutorial uses the open-source Inkeep agents framework (@inkeep/agents-ui) which you self-host with your own LLM key β€” no per-seat or per-call fee to Inkeep for the chat itself.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  VendorOps  (Next.js, :3000)                        β”‚
β”‚                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Vendor profile                                β”‚ β”‚
β”‚  β”‚  Status: blocked                               β”‚ β”‚
β”‚  β”‚  Missing docs: W-9, certificate of insurance   β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚       β”‚ sendVendorUnblockAttempt()                  β”‚
β”‚       β”‚ POST /demo/actions                          β”‚
β”‚       β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Context fetch                                 β”‚  β”‚
β”‚  β”‚  GET /context/{session_id}                     β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚       β”‚                                             β”‚
β”‚       β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  InkeepEmbeddedChat                           β”‚  β”‚
β”‚  β”‚  β†’ explains missing compliance documents      β”‚  β”‚
β”‚  β”‚  β†’ points admin to request-documents flow     β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ POST /demo/actions
               β”‚ GET  /context/{session_id}
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Bridge  (FastAPI, :8787)                           β”‚
β”‚                                                     β”‚
β”‚  AsyncConnectorClient β†’ AsyncContextStore           β”‚
β”‚    + AsyncSessionSummarizer (rolling 30-event windowβ”‚
β”‚      per session)                                   β”‚
β”‚                                                     β”‚
β”‚  Context: vendor_unblock_attempt + blocked status   β”‚
β”‚    + missing compliance documents                   β”‚
β”‚                                                     β”‚
β”‚  GET  /context/{session_id}  β†’ assembled context   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Inkeep agents framework  (:3002)                   β”‚
β”‚  (self-hosted, your LLM key)                        β”‚
β”‚                                                     β”‚
β”‚  project: vendor-ops                                β”‚
β”‚  agent:   vendor-support                            β”‚
β”‚  sub-agent: compliance-support-worker               β”‚
β”‚                                                     β”‚
β”‚  InkeepEmbeddedChat ↔ AI sub-agent                  β”‚
β”‚  introMessage ← context from /context/{session_id} β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Two inputs feed the context layer: the vendor profile reports the admin’s action directly to the bridge (POST /demo/actions), and the bridge keeps the vendor’s blocked status plus missing compliance-document state available for chat grounding. The bridge owns all context logic; Inkeep stays a clean conversational surface. The GET /context/{session_id} endpoint assembles a human-readable summary of the admin’s recent activity and the vendor’s compliance state. When the admin opens chat, this summary becomes the introMessage passed to InkeepEmbeddedChat β€” so the AI’s first message references the blocked vendor and missing documents, not a generic greeting.

The tutorial

  1. Step 1 β€” Connect real-time events β€” Build the vendor-management frontend, wire unblock attempts and vendor context into a FastAPI bridge, run the Inkeep agents framework in Docker, and embed InkeepEmbeddedChat. At the end of this step you have a working AI chat widget on the vendor profile. ~45 minutes.
  2. Step 2 β€” Define proactive triggers β€” Add blocked-vendor detection to the bridge, wire the guidance channel to the frontend, and build the proactive handoff that opens Inkeep chat with the vendor’s missing compliance documents pre-loaded. ~45 minutes.