links.10x.in/docs/end-user/agentic-pages-implementation-handoff Published:

Agentic Pages Implementation Handoff

Use this handoff when you are enabling, validating, or troubleshooting 10x Agentic Pages for an external integration. It is intentionally more detailed than the user guide.

Runtime model

The public page agent combines:

  • public page context from the current published page
  • related published page summaries from the same handle
  • handle knowledge retrieved with containerTags: ["public-page-agent"]
  • Bedrock generation for the final answer through AI SDK streaming
  • AI SDK UI message parts for the browser answer and generated lead qualification section
  • browser rendering through /assets/public-page-agent.js

Embeddings stay on the existing Titan path:

amazon.titan-embed-text-v2:0

Generation uses the configured public-page model:

PUBLIC_PAGE_AGENT_MODEL_ID

The default planned generation target is:

anthropic.claude-haiku-4-5-20251001-v1:0

The configured value may be a Bedrock model ID, geo inference ID, global inference ID, or full inference-profile ARN. Before production traffic, verify the exact configured value in the target AWS account and region with a direct Bedrock invoke smoke test.

Availability gates

The visitor route is unauthenticated, but availability is enforced internally per handle.

Required gates:

  • Global switch: PUBLIC_PAGE_AGENT_ENABLED.
  • Handle override: PUBLIC_PAGE_AGENT_ALLOWED_HANDLES.
  • Tenant entitlement for non-allowlisted handles: marketing_tools.
  • Public route disabled response: return non-leaky 404 for anonymous traffic.
  • Contract shorthand: disabled handle returns non-leaky 404.

Do not expose whether a handle exists, whether a tenant is entitled, or which gate failed.

Operator setup sequence

Use this sequence when enabling Agentic Pages in a new environment or for a new handle.

  1. Confirm the runtime route is deployed:
   POST /v2/public/pages/{handle}/{pageSlug}/agentic-question
   POST /v2/public/pages/{handle}/{pageSlug}/agentic-chat
  1. Confirm the page shell can inject the widget asset:
   <script id="tenx-public-page-agent-config" type="application/json">...</script>
   <script async src="/assets/public-page-agent.js"></script>
  1. Set runtime availability:
   PUBLIC_PAGE_AGENT_ENABLED=true

or add the handle to:

   PUBLIC_PAGE_AGENT_ALLOWED_HANDLES=acme,productivity-ops
  1. Set the model:
   PUBLIC_PAGE_AGENT_MODEL_ID=us.anthropic.claude-haiku-4-5-20251001-v1:0
  1. If the environment reads these values from SSM/CDK context, refresh the runtime SSM context before synth and deploy. Then deploy the API stack, the public page shell asset, and any edge/site asset changes needed for /assets/public-page-agent.js.
  1. Smoke test from the public host, not only the API host. The HTML response must include tenx-public-page-agent-config, /assets/public-page-agent.js, and either the inline mount or the floating launcher path.

JWT cannot enable the anonymous route by itself. JWT creates and publishes handle-owned content; deployment and environment configuration make the visitor runtime available.

Creator JWT setup sequence

Use a creator/operator JWT only for setup calls:

export API_BASE="https://ai.10x.in"
export HANDLE="acme"
export PAGE_SLUG="launch-agent"
export JWT_TOKEN="<jwt-token>"

Create or update the page with template: "html_render", publish it, then seed public-agent KB documents:

POST /v2/handles/{handle}/pages
PUT /v2/handles/{handle}/pages/{pageSlug}
POST /v2/handles/{handle}/pages/{pageSlug}/publish
POST /v2/handles/{handle}/knowledge/documents
POST /v2/handles/{handle}/knowledge/query

After setup, validate through anonymous public routes:

POST /v2/public/pages/{handle}/{pageSlug}/agentic-question
POST /v2/public/pages/{handle}/{pageSlug}/agentic-chat

If setup calls succeed but anonymous routes return 404, the likely issue is availability/deployment, not the JWT.

Public route contract

Route registry entry:

{
  "method": "POST",
  "pathTemplate": "/v2/public/pages/{handle}/{pageSlug}/agentic-question",
  "authMode": "none",
  "module": "pages",
  "operation": "agenticQuestion"
}

The route mirrors existing public page siblings:

POST /v2/public/pages/{handle}/{pageSlug}/access-check
POST /v2/public/pages/{handle}/{pageSlug}/checkout
POST /v2/public/pages/{handle}/{pageSlug}/agentic-question
POST /v2/public/pages/{handle}/{pageSlug}/agentic-chat

Request:

{
  "question": "What support is included?"
}

Limits:

  • question is required.
  • Maximum question length is 500 characters.
  • A 501-character request returns 400 question_too_long.

Response:

{
  "answerMarkdown": "Answer text",
  "evidenceCards": [],
  "ctaCards": [],
  "followUps": [],
  "degraded": false,
  "retrievalMode": "page+related_pages+vector",
  "modelId": "anthropic.claude-haiku-4-5-20251001-v1:0"
}

Streaming UI route registry entry:

{
  "method": "POST",
  "pathTemplate": "/v2/public/pages/{handle}/{pageSlug}/agentic-chat",
  "authMode": "none",
  "module": "pages",
  "operation": "agenticChat"
}

Streaming request:

{
  "messages": [
    {
      "role": "user",
      "parts": [{ "type": "text", "text": "What support is included?" }]
    }
  ]
}

Streaming response:

content-type: text/event-stream

The stream uses AI SDK UI message parts. The model lane uses PUBLIC_PAGE_AGENT_MODEL_ID with the Amazon Bedrock provider. Retrieval, availability, teaser-safe paid-page context, 500-character latest-user-message limit, and non-leaky 404 behavior must match the legacy JSON route.

Page embed contract

Eligible 10x public pages receive a JSON config script and the public agent asset from the page shell.

Inline mode:

<div id="tenx-public-page-agent-inline"></div>

Alternative inline mode:

<div data-tenx-public-page-agent-inline></div>

If an inline mount exists, the widget renders in place and hides the floating launcher. If no inline mount exists, the widget appends a floating Ask launcher.

The browser widget calls the same-origin streaming public route with no visitor credentials:

POST /v2/public/pages/{handle}/{pageSlug}/agentic-chat

The legacy JSON endpoint remains available for non-widget browser Q&A and API validation:

POST /v2/public/pages/{handle}/{pageSlug}/agentic-question

Rich HTML page contract

The authenticated page APIs store content and teaser as HTML. For template: "html_render", the public renderer wraps the stored content inside the standard page shell. The content payload should be an HTML fragment:

<main>
  <section>
    <h1>Launch Agent</h1>
    <p>Approved public context for the assistant.</p>
  </section>
  <section>
    <h2>Ask the launch guide</h2>
    <div id="tenx-public-page-agent-inline"></div>
  </section>
</main>

Do not send a complete document with duplicate <html>, <head>, or <body> tags. The shell owns the document wrapper, meta tags, default typography, and public-agent script injection.

Operational rules:

  • Put critical public facts in text nodes so retrieval can use them.
  • Keep images and visual assets optional for comprehension.
  • Place the inline mount at the interaction point. Without it, the widget falls back to floating mode.
  • Treat page HTML as trusted creator-authored public HTML. Never copy untrusted visitor HTML into content.
  • Do not include secrets, private signed URLs, internal dashboard links, or customer-specific data.
  • For paid pages, the anonymous agent must use teaser-safe public context only. Keep paid-only claims out of teaser.

Generated lead form contract

The streaming route exposes one model tool to the AI SDK generation call:

renderLeadQualificationSection

Tool output shape:

{
  "sectionId": "lead-qualification",
  "collapsedTitle": "Plan your next step",
  "collapsedBody": "Share a few details and the team can follow up.",
  "html": "<form>...</form>",
  "fields": [],
  "submitLabel": "Send",
  "contextDisclosure": "This form includes the current page, question, answer, evidence titles, and retrieval mode.",
  "dynamicView": {
    "headline": "Launch support workspace",
    "subhead": "A prompt-specific summary rendered by the host React widget.",
    "recommendedPath": {
      "label": "Best next move",
      "body": "Share the launch goal and blocker so the owner can route the follow-up."
    },
    "momentumSteps": [],
    "fitSignals": [],
    "questionChips": [],
    "visualAccent": "launch"
  },
  "leadContext": {}
}

Server-side validation requirements:

  • Generated HTML max size: 12 KB.
  • Disallow script, inline on* attributes, and external images, scripts, or styles.
  • Fields max: 8.
  • Required field: email.
  • Optional native fields: name, company, phone, and message.
  • Up to 3 generated qualification fields.
  • Field names must match the lead field key rules.
  • dynamicView is rendered by the host React widget, not by iframe HTML. It may include a prompt-specific headline, subhead, recommended path, 3 to 4 momentum steps, 2 to 4 fit signals, follow-up chips, and an accent of signal, launch, support, or proof.

Browser containment and submission requirements:

  • Render generated HTML only inside <iframe sandbox="allow-forms allow-scripts">.
  • Do not inject generated HTML into the host page DOM.
  • Iframe posts form data to the parent widget with postMessage.
  • Parent widget validates the payload, attaches disclosed leadContext, and submits through POST /v2/public/handles/{handle}/leads with credentials: "omit".
  • Visitor-facing disclosure must state that the answer context is included with the lead.

Generated HTML is deliberately narrower than page HTML. It is form HTML only. The server removes or blocks script, style, iframe, object, embed, link, img, inline event handlers, inline styles, and external src, href, or action values. Use dynamicView and native widget components for rich presentation instead of trying to ship arbitrary HTML, CSS, or JavaScript through the model.

Structured rich-card KB contract

The streaming route can expose additional native UI tools when retrieved public KB includes recognized structured blocks. The productivity lesson-card lane uses:

productivity_lesson_card

and streams:

renderProductivityLessonCards

Document pattern:

{ "lessonId": "time-blocking", "title": "Time Blocking", "category": "Planning", "summary": "Reserve focused calendar blocks for one kind of work.", "whenToUse": ["Context switching is high"], "steps": ["Choose one priority", "Block 45 minutes", "Review the result"], "tryNow": "Block the next 45 minutes for one task.", "relatedTactics": ["daily shutdown", "single-tasking"], "sourceDisclosure": "Public productivity guide." }

Rules:

  • The model must preserve values from retrieved snippets. It should not invent lesson IDs, claims, or steps.
  • The widget renders lesson cards as native React UI.
  • The structured card block is public KB, so it must not contain paid-only or private content.
  • Use this pattern only for known native widgets. Arbitrary rich HTML still belongs in the page body or the sandboxed lead-form iframe.

KB setup and steering

Only public-agent KB documents should use:

{
  "containerTags": ["public-page-agent"]
}

Recommended document categories:

  • Public facts: feature claims, support windows, launch steps, proof points.
  • Pricing boundaries: what can be answered publicly and what requires sales.
  • Competitor guidance: approved comparisons and fit criteria.
  • Escalation policy: when to route to support, sales, or implementation.
  • Refusal rules: secrets, paid content, private customer data, and internal-only processes.

Keep documents short. Prefer several single-purpose documents over one broad policy blob. Public-agent KB is a steering surface, not a private memory store.

Paid content and leak safety

For PUBLIC pages, page context can use the published content body.

For PAID pages, page context must use only teaser-safe public content. The assistant must not read or reveal paid body content to anonymous visitors.

Validation marker pattern:

  • Paid page body contains a private marker, for example DO-NOT-LEAK-APQA-PRIVATE.
  • Paid teaser excludes that marker.
  • A public agent question about the marker must not include it in the API response or UI.

Abuse controls and logs

V1 controls:

  • API Gateway throttle: burst 40, rate 20.
  • 500-character question cap.
  • Safe Markdown rendering in the browser asset.
  • Generated HTML is constrained to the sandboxed iframe.
  • Lead submission uses the native public lead endpoint, not information-request submissions.
  • No logging of question text.
  • No logging of retrieved page or KB content.

Allowed structured log metadata:

handle
pageSlug
modelId
retrievalMode
degraded
snippetCount
tookMs

Do not add visitor-level metering until the feature proves useful. If later added, keep it separate from the V1 safety/logging contract.

Staging validation

Use persistent fixtures so validation can repeat after every deploy.

Public page fixture:

  • Published and visitor-visible.
  • Contains the phrase: onboarding checklists, launch templates, and implementation support.
  • Contains the inline mount when validating chat-first pages.

KB fixture:

{
  "title": "Public Agent QA Knowledge Fixture",
  "source": "public-agent-validation",
  "contentType": "text/plain",
  "containerTags": ["public-page-agent"],
  "content": "QA support code is APQA-2026. The handoff window is two business days."
}

Paid leak fixture:

  • Published as PAID.
  • Body contains DO-NOT-LEAK-APQA-PRIVATE.
  • Teaser excludes DO-NOT-LEAK-APQA-PRIVATE.

Blocking checks:

  • Focused tests pass for route, shell, asset, and stack coverage.
  • Bedrock preflight succeeds for the exact configured PUBLIC_PAGE_AGENT_MODEL_ID.
  • Direct KB query with containerTags: ["public-page-agent"] returns APQA-2026.
  • Public page-context question returns 200, answer, evidence cards, CTA cards, and follow-ups.
  • Streaming chat question returns 200 with text/event-stream and one generated lead section tool part.
  • Generated lead section renders inside the iframe sandbox and posts to POST /v2/public/handles/{handle}/leads.
  • RAG question returns APQA-2026, two business days, and a kb_doc evidence card.
  • Unsupported secret question abstains.
  • 501-character question returns 400 question_too_long.
  • Disabled handle returns non-leaky 404.
  • Paid private marker never appears in API output, UI output, or logs.

Local verification commands

Run the focused tests before deploying changes to the public agent surface:

npx vitest run \
  test/api.public-page-agent.test.ts \
  test/api.pages-public-agent-shell.test.ts \
  test/api.route-registry.contract.test.ts \
  test/public-page-agent-asset.test.ts \
  --minWorkers=1 \
  --maxWorkers=1

When stack resources or throttling change, also run:

npx vitest run test/stack.creator-economy.contract.test.ts --minWorkers=1 --maxWorkers=1

Run GitNexus checks in this workspace:

npx gitnexus analyze
gitnexus impact <symbol-or-flow>
gitnexus detect-changes

If your installed GitNexus CLI does not support detect-changes, run the closest available status/diff command and record the limitation in the release notes.

Related docs