Lumen ChartsLumen Charts
AI integration

Server-side models

Run the model on your server while the chart stays in the browser.

Download Markdown

Most AI integrations call the model from a server while the chart runs in the browser. A remote session keeps the chart, its fences and its native owners in the browser and gives the server the same command facade and model tools.

// Browser
import { serveAutomation } from '@lumencharts/chart-automation/sdk';

const sdk = await chart.openAutomation({ policy: { effects: ['read', 'mutation'] } });
const server = serveAutomation(sdk, {
  captureResult: async capture => ({ attachmentId: await upload(capture.blob) }),
});
myChannel.onCall(async (call, signal) => myChannel.reply(await server.handle(call, signal)));
startTurn({ chart: server.snapshot() });
// Server
import { createAutomationTools, connectAutomation } from '@lumencharts/chart-automation/sdk';

const chart = connectAutomation(turn.chart, {
  send: (call, signal) => myChannel.call(call, signal),
});
const tools = createAutomationTools(chart, { use: [budgets, auditLog], imageResult: toProviderImage });
const system = chart.instructions();

Protocol

MessageShape
Snapshot{ version: 1, target, capabilities, instructions }, sent by the browser at the start of a turn and again when capabilities().revision changes (chart.update(snapshot))
Call{ version: 1, requestId, target, name, commandVersion?, input, timeoutMs? }
Result{ version: 1, ok: true, value, target } or { version: 1, ok: false, code, target }

name is a command name or one of data.series, data.read, data.requestHistory and capture.image. Timeouts are relative, so server and browser clocks need not agree; the remote session also enforces the snapshot's deadline ceiling locally. Results carry the chart's current target, so the server learns about a navigation and later calls are fenced to the new chart. A call built against a different commandVersion rejects with unsupported. Errors carry a chart error code and, for rejected input, optional details ({ path, reason }), never a message. parseAutomationRemoteResult validates and bounds details and drops anything else.

Capture is advertised only when the browser supplies captureResult, which turns the PNG into something your channel can carry; on the server, capture.image() and the capture_image tool resolve to that value.

Transport responsibilities

The SDK is transport-neutral. Your channel owns:

  • delivery and reconnection;
  • durable replay by requestId: a repeated call returns the stored result instead of running twice;
  • rejecting a known requestId sent with different input;
  • forwarding cancellation through the signal on both sides.

server.handle never rejects; it always resolves to a result. chart.destroy() aborts in-flight calls on the server side, and later calls reject with unavailable.

On this page