Shopping agent (ADK + AG-UI)
The hidden, more capable assistant that actually takes action on your behalf.
NShop ships a second AI surface at /{locale}/x/assistant. It's not
linked from the storefront and is noindex — obscurity, not access
control — because the real protection is the per-tool authentication
described below.
The shopping agent is a separate Python Cloud Run service built on three pieces:
- ADK (Anthropic's Agent Development Kit) for the agent loop and tool orchestration.
- AG-UI for generative UI — the agent doesn't just reply in text, it renders product cards, tables, and order summaries inline.
- Vertex Gemini 2.5 Flash for the underlying model, pinned to
europe-west4.
How the request flows
shopper → Next.js BFF (/api/agent/[...path])
↓ verifies __session cookie + tenant
↓ mints 5-minute HS256 JWT with { uid?, tenantId, role?, threadId }
↓ proxies AG-UI SSE
↓
Python agent (ADK + AG-UI)
↓ verifies JWT → Principal
↓ runs tool calls; each tool re-checks Principal
↓
Firestore / Storage / Stripe (server-side)- The Next.js app is the only thing the shopper's browser sees. It
resolves the tenant from the subdomain (
getTenantSlug()), verifies the session, and proxies the SSE stream. - The JWT is short-lived (5 minutes) and signed with a secret in Secret Manager. The Python service rejects anything that doesn't verify.
- Inside the Python service, the
Principalis attached to every tool call. Public tools accept an anonymous principal; private tools (cart, orders, preferences) reject it.
What it can render
- Product cards with image, price, stock, and an Add to cart button wired to the agent itself — no leaving the conversation to act.
- Order detail blocks with status timeline, tracking link, and items.
- Comparison tables when the shopper asks "which of these is better for…".
- Preference summaries ("I have you down for size M and a preference for organic cotton — should I prioritize that?").
What makes it "agentic"
The agent decides which tools to call and in what order. A single turn might:
- Run semantic search.
- Fetch full detail on two candidates.
- Compare them.
- Read the shopper's saved size preference.
- Render an Add-to-cart card for the right variant.
The shopper writes one sentence; the agent does the rest.
Persistence
- Logged-in threads live in Firestore at
/chat_threads. - Anonymous threads live in
localStorage, signed with an HMAC key stored server-side at/anonymous_chat_keys/{threadId}(server-only access, 7-day TTL). The key prevents anyone from forging history that the agent later trusts. - A shopper can sign in mid-conversation and adopt their anonymous thread into their account.
Why a separate service?
ADK is a Python framework. Putting it in its own Cloud Run service
(python-agent/) lets it scale independently, deploy on its own
schedule (path-filtered Cloud Build trigger), and use a different model
without rebuilding the Next.js app.
See the runbook in docs/runbooks/agent-service.md for operational
details (deployment, secrets, logs).