Skip to main content
@craft-ts
LearnLearn with EffectAI agentsGuideReference
@craft-ts/core@craft-ts/component@craft-ts/dev-tools@craft-ts/effect@craft-ts/style@craft-ts/style-testing@craft-ts/i18n@craft-ts/i18n-effect@craft-ts/mcp
ExamplesMigrationEffect compatibility & maturityAdopting CraftTS progressivelyPress kitRoadmapBacklog
Beta
  • Learn
  • Learn with Effect
  • AI agents
  • Guide
  • Reference
  • Packages
  • Resources

i.AI agents

  • Overview
  • Coding agents
  • MCP tools
  • Live page MCP
  • Send context to AI
  1. AI agents
  2. Send context to AI

Send application context to AI#

provideSendContextToAi adds a developer-oriented context inspector to a Craft application. It is useful when an AI assistant needs more than a copied error message: the selected component, the recent user journey, the relevant app state, and optionally the DOM and computed CSS.

Typical uses include:

  • asking an AI assistant to explain or fix a broken screen;

  • preparing a reproducible bug report or a support ticket;

  • investigating a failed HTTP request, navigation, mutation, or query;

  • sending a consistent, structured context to an internal debugging agent.

The feature is user-driven. It does not call an AI service by itself. Without an endpoint, everything stays in the browser and the user copies the prompt or the timeline when they choose to. The required recording option decides when capture starts: true starts a session clip automatically at app startup; false waits until the user clicks Record. In either mode, the user can stop and manually start recording from the timeline controls. Events are only captured while a recording clip is active.

Minimal setup#

Register the provider once in the application providers. The default UI then adds an AI context launcher in the bottom-right corner and a context menu to Craft component hosts. The minimal setup opts in to session recording:

ts
export const minimalAiContextProviders = [provideSendContextToAi({ recording: true })];

The two entry points are equivalent:

  • open the launcher to start with an empty context, then interact with the app;

  • right-click a component to start with that component already selected.

From the chat, the user can add more elements with another right-click, remove selected elements, write an instruction, record or clear the timeline, and choose which sections to include in the generated Markdown prompt.

What is collected#

The session combines several kinds of context:

  • Selected elements: tag name, text, outer HTML, and optionally a selector.

  • Component information: the host name, Craft host tags, click coordinates, the clicked element, and truncated host HTML.

  • Timeline: DOM interactions, HTTP requests, router activity, primitive activity, and app snapshot reports. HTTP and navigation entries are linked by operation and correlation IDs when those services provide them.

  • App snapshots: the reports emitted by the app snapshot registry while the context is being prepared.

  • DOM and CSS captures: the selected component or the full page, including computed styles. These captures are optional because they can be large and briefly pause the page while they are collected.

The default prompt contains selected elements, component information, the timeline summary, and app snapshots when they exist. Timeline JSON and DOM/CSS captures are opt-in. The checkboxes in the chat change the Markdown prompt; the webhook also receives the structured fields so an agent can process them without parsing Markdown.

The chat also supports recording a named clip. A clip is a subset of the timeline, which is useful when an investigation contains several unrelated interactions. Copy JSON copies a versioned export of the full session, regardless of which clip is selected. Copy prompt builds the AI-oriented Markdown document. Clear removes the current timeline and, if recording was active, starts a fresh clip so the next reproduction can be captured.

Export and replay a debugging session#

Use the timeline's Record control while reproducing an issue, then choose Copy JSON to copy the complete session. The export includes the starting URL, the event timeline, clips, and recorded HTTP request/response data. DOM events include a replay target and action; form values and relevant keyboard details are included when available. Password fields and fields whose names indicate secrets are omitted, and the normal send-context redactor runs before data is exported. Events from the debugging overlay itself are excluded.

In the local app, open the context panel, paste the JSON into Replay a session, and choose Validate. Invalid JSON, unsupported versions, and sessions marked as truncated are rejected. Retention can evict old events, so an export with lost events is explicitly marked incomplete and cannot be replayed as a complete session.

For the most useful replay, first reload the local app on the recorded path, then reopen the panel, paste the export again, and validate it. The origin in the export may belong to another environment; replay compares request paths and uses the current local app. It re-runs the app's code and interactions; it does not restore the app's complete initial state.

After validation, use:

  • Play to replay interactions at the intervals recorded in the session;

  • Pause to hold replay before the next interaction;

  • Next step to dispatch one interaction and advance Craft's virtual clock to that event's recorded time;

  • Stop to end replay and restore the normal Craft clock and fetch.

Recorded HTTP responses are returned for matching fetch requests. A request with no recorded match stops replay and is rejected; it is never sent through fetch to the server. Matching uses the request method, local path and query, body, and recorded order. Craft timers scheduled through CraftTemporalRuntime and progressive scheduleFor rendering use the replay clock: they remain paused between steps and run when replay advances time. Direct calls by the application to native timers or animation-frame APIs are outside this virtual clock's control.

Events that include a captured state can be compared with state observed after replay. A mismatch is reported in the panel so the interaction can be investigated; replay does not force the recorded state back into the app.

Send the context to an agent#

Pass a browser-accessible webhook URL to enable the Send action:

ts
export const aiContextProviders = provideSendContextToAi({
  recording: true,
  endpoint: 'https://agent.example.com/hooks/context',
});

The browser sends a JSON POST with this versioned shape:

json
{
  "version": 1,
  "prompt": "# Instruction\nInvestigate this screen",
  "instruction": "Investigate this screen",
  "selectedElements": [],
  "events": [],
  "snapshot": [],
  "captures": {},
  "component": {
    "hostName": "OrdersPage",
    "tagList": ["component:OrdersPage#1"],
    "coords": { "x": 120, "y": 80 },
    "outerHTML": "<section>…</section>"
  }
}

prompt is generated from the instruction, the selected options, and the structured fields. component is omitted when the chat was opened from the launcher without a captured component. captures.component and captures.page are present only when their corresponding DOM/CSS options were selected. Events generated by the webhook request itself are excluded from the context sent to that webhook.

Any 2xx response is successful, including 200, 202, and 204. Network failures, timeouts, and non-2xx responses are shown in the chat. Retry reuses the exact same payload, and Copy payload copies that payload only after a failed request.

The endpoint is application configuration shipped to the browser, not a secret. It must allow the application's origin through CORS and accept JSON POST requests. Put authentication and secret management in a protected same-origin proxy or agent gateway.

Configure the webhook#

provideSendContextToAi currently accepts the browser-accessible endpoint. Omit it to keep the experience copy-only, or pass a URL to enable sending:

ts
export const customizedAiContextProviders = provideSendContextToAi({
  recording: true,
  endpoint: '/internal/ai/context',
});

Treat that URL as public application configuration. Put authentication, redaction, and any tenant-specific policy in a protected same-origin proxy or agent gateway; never put credentials in the browser bundle.

The session and its record controller are also injectable:

ts
import {
  SEND_CONTEXT_RECORD_CONTROLLER,
  SEND_CONTEXT_SESSION,
} from '@craft-ts/component';
import { ɵinject as inject } from '@craft-ts/core';

const record = inject(SEND_CONTEXT_RECORD_CONTROLLER);
record.startRecord('Checkout failure');

// Later, from the same application flow:
record.stopRecord();
const summary = record.exportSummary();
const json = record.exportJson();

const session = inject(SEND_CONTEXT_SESSION);
session.capture('custom', 'emitted', {
  name: 'checkout.validation',
  state: { step: 'payment' },
});

Use the record controller for clips and the session for low-level event emission, subscription, clearing, and programmatic export.

Customize the UI with DI#

There are three levels of UI customization:

ProviderWhat it replaces or addsWhen to use it
provideSendContextChatComponent(() => MyChat)The default chat panelKeep the built-in launcher and context menu, but replace the panel
provideSendContextUiRenderer(() => MyRenderer)The complete rendererOwn the launcher/chat lifecycle and render the whole experience
SEND_CONTEXT_LAUNCHER_COMPONENT / SEND_CONTEXT_CONTEXT_MENU_COMPONENTThe floating launcher or right-click menuMatch the application's controls or visual language

The complete renderer receives SendContextUiContext. It exposes the live session, events, clips, selected targets, captured payload, DOM capture element, recording state, endpoint, and operations such as addTarget, removeTarget, selectClip, and close.

ts
import {
  provideSendContextChatComponent,
  provideSendContextUiRenderer,
  type SendContextUiContext,
} from '@craft-ts/component';

// A chat replacement keeps the default surrounding behavior.
provideSendContextChatComponent(() => MyChat);

// A complete renderer receives the live context as its `context` input.
provideSendContextUiRenderer(() => MyRenderer);

// MyRenderer's input contract is:
// { context: Input<SendContextUiContext>; onClose: Output<() => void> }

provideSendContextChatSection, provideSendContextChatAction, and provideSendContextExportSection are multi providers intended for a custom renderer. They let feature libraries contribute sections, commands, or export views without depending on one global renderer. The built-in chat does not render those extension entries itself; a custom renderer reads them from SendContextUiContext.

For example, a feature can contribute an action that starts a named clip:

ts
import { provideSendContextChatAction } from '@craft-ts/component';

const providers = [
  provideSendContextChatAction({
    id: 'record-checkout',
    label: 'Record checkout flow',
    run: (context) => context.session.startRecord('Checkout flow'),
  }),
];

The UI provider tokens are regular DI contracts, so a custom launcher or menu can be registered directly:

ts
import {
  SEND_CONTEXT_CONTEXT_MENU_COMPONENT,
  SEND_CONTEXT_LAUNCHER_COMPONENT,
} from '@craft-ts/component';

const providers = [
  {
    provide: SEND_CONTEXT_LAUNCHER_COMPONENT,
    useValue: MyLauncher,
  },
  {
    provide: SEND_CONTEXT_CONTEXT_MENU_COMPONENT,
    useValue: MyContextMenu,
  },
];

Complete integration example#

An application can combine the default UI, a protected endpoint, stricter retention, and application-specific event filtering:

ts
import { craftAppConfig } from '@craft-ts/core';
import {
  provideSendContextEventFilter,
  provideSendContextToAi,
  SEND_CONTEXT_RETENTION_POLICY,
} from '@craft-ts/component';

export const appConfig = craftAppConfig({
  providers: [
    provideSendContextToAi({
      recording: true,
      endpoint: '/internal/ai/context',
    }),
    {
      provide: SEND_CONTEXT_RETENTION_POLICY,
      useValue: { maxEvents: 250, maxBytes: 1024 * 1024 },
    },
    provideSendContextEventFilter((event) => event.name !== 'healthcheck'),
  ],
});

The server-side endpoint should validate version, authenticate the user, apply any additional server-side redaction, and then forward either prompt or the structured context to the selected agent.

←Live page MCP

On this page

  • Minimal setup
  • What is collected
  • Export and replay a debugging session
  • Send the context to an agent
  • Configure the webhook
  • Customize the UI with DI
  • Complete integration example

@craft-ts · MIT licensed

GitHubnpm

Search