10xDotIn Developer Docs

Agentic Pages Implementation Handoff

Operational and implementation handoff for public agentic pages.

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. The streaming agentic-chat route also has a fallback generation target:

PUBLIC_PAGE_AGENT_FALLBACK_MODEL_ID

The default fallback target is:

openai.gpt-oss-20b-1:0

Set the fallback value to none, off, false, or disabled to disable fallback. Before production traffic, verify both configured values in the target AWS account and region with direct Bedrock smoke tests.

Bedrock Mantle Gemma 4 31B model option

The streaming chat route supports provider-prefixed model ids. Unprefixed values and bedrock: values use the existing Amazon Bedrock Runtime provider. bedrock-mantle: values use the Bedrock Mantle OpenAI-compatible Chat Completions endpoint.

Gemma 4 31B must use Mantle:

PUBLIC_PAGE_AGENT_MODEL_ID=bedrock-mantle:google.gemma-4-31b
PUBLIC_PAGE_AGENT_FALLBACK_MODEL_ID=us.anthropic.claude-haiku-4-5-20251001-v1:0
PUBLIC_PAGE_AGENT_MANTLE_BASE_URL=https://bedrock-mantle.us-east-1.api.aws/openai/v1
PUBLIC_PAGE_AGENT_MANTLE_TIMEOUT_MS=8000

The Lambda uses @aws/bedrock-token-generator to mint a short-term Bedrock bearer token at runtime. Do not store a long-term Bedrock API key in SSM. The API Lambda role must allow bedrock:CallWithBearerToken with bedrock:bearerTokenType set to SHORT_TERM.

The Mantle lane does not ask Gemma to emit AI SDK tool calls. It asks for strict JSON, validates the payload server-side, normalizes the generated lead section through the existing lead-section safety rules, and emits the same UI-message SSE parts used by the React widget. If Mantle transport or payload validation fails, the route logs public_page_agent_chat_primary_failed without visitor text or retrieved snippets and uses fallback to Haiku when configured.

Example prod SSM switch after the code is deployed:

aws ssm put-parameter \
  --region us-east-1 \
  --profile 10xdotin-target-prod-deploy \
  --name /10x-dot-in/prod/api/public-page-agent-model-id \
  --type String \
  --value 'bedrock-mantle:google.gemma-4-31b' \
  --overwrite

aws ssm put-parameter \
  --region us-east-1 \
  --profile 10xdotin-target-prod-deploy \
  --name /10x-dot-in/prod/api/public-page-agent-fallback-model-id \
  --type String \
  --value 'us.anthropic.claude-haiku-4-5-20251001-v1:0' \
  --overwrite

Rollback is config-first. Set PUBLIC_PAGE_AGENT_MODEL_ID back to Haiku, refresh runtime config through the normal release process, and revalidate /agentic-chat. Code rollback is only needed if the Bedrock Runtime fallback path breaks.

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:

``text 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:

```html

```

  1. Set runtime availability:

``text PUBLIC_PAGE_AGENT_ENABLED=true ``

or add the handle to:

``text PUBLIC_PAGE_AGENT_ALLOWED_HANDLES=acme,productivity-ops ``

  1. Set the model:

``text PUBLIC_PAGE_AGENT_MODEL_ID=us.anthropic.claude-haiku-4-5-20251001-v1:0 PUBLIC_PAGE_AGENT_FALLBACK_MODEL_ID=openai.gpt-oss-20b-1: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.

Runtime fallback and alerts

The streaming route first tries PUBLIC_PAGE_AGENT_MODEL_ID. If model streaming fails, it logs public_page_agent_chat_primary_failed without question text or retrieved content and retries once with PUBLIC_PAGE_AGENT_FALLBACK_MODEL_ID. If the fallback also fails, it logs public_page_agent_chat_failed and returns a non-leaky SSE error event:

event: error
data: {"error":"chat_unavailable"}

CloudWatch metric filters emit TenXDotIn/PublicPageAgent metrics for both log events. The alarm public-page-agent-primary-model-failures catches primary-model degradation even when fallback protects visitors. The alarm public-page-agent-chat-failures catches visitor-visible failures after all configured models fail.

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

Widget customization contract

The resolved widget customization config is injected through tenx-public-page-agent-config.

Resolution order:

built-in variant defaults -> handle defaults -> page overrides -> embed safe overrides

Rich slot HTML is authenticated-only. Public embeds can select variants and safe tokens with JSON or data-*, but cannot provide rich HTML or CSS.

Generated lead form HTML remains sandboxed in the iframe. Custom leadIntro content renders above the lead card/frame and must not replace native lead submission.

Validation checklist:

  • Reject scripts, iframes, forms, inputs, inline event handlers, external scripts/styles, unsafe URLs, and unsafe CSS.
  • Cap rich slot HTML and CSS sizes.
  • Clamp starter chip counts and copy lengths.
  • Keep /agentic-chat and /v2/public/handles/{handle}/leads same-origin and credentialless.

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.

Group-buy coordinator safety contract

Agent-managed group buying uses stored visitor skill.md instructions. Mutating authority in v1 is limited to group-buy interest creation or update and strict-consensus handle-owned calendar booking.

The markdown must include deterministic constraints:

{
  "groupBuy": {
    "autoCommitInterest": true,
    "quantity": 2,
    "maxUnitPriceCents": 6000,
    "currency": "usd"
  },
  "calendar": {
    "autoBook": true,
    "eventSlug": "group-buy-call",
    "attendeeEmail": "buyer@example.com",
    "attendeeName": "Buyer",
    "timeZone": "UTC",
    "availableWindows": [
      { "start": "2026-06-20T13:00:00.000Z", "end": "2026-06-25T18:00:00.000Z" }
    ],
    "notifyByEmail": true,
    "allowGroupNotification": true
  }
}

Agent-managed interest does not auto-close, publish, pay, unlock offers, or message vendors. Visitors do not connect calendars. The coordinator books only against the handle-owned scheduling event and only when every matched participant has calendar.autoBook: true.

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.

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.

Updated Jun 19, 2026