Lumen ChartsLumen Charts
AI integration

Native commands and model tools

Native chart commands and the matching tool definitions for AI models.

Download Markdown

Open a session with native commands

const sdk = await widget.activeChart().openAutomation({
  commands: ['drawings', 'studies', 'settings'], // the default
  policy: { effects: ['read', 'mutation'] },
});
console.log(sdk.capabilities().commands.map(command => command.name));

openAutomation requests assets/chart-automation.js relative to the configured library base on first use. Creating a widget alone never requests it. Concurrent loads are deduplicated; failed loads can be retried, and a loading failure leaves the ordinary chart usable. The ai_commands widget option does not load assets or grant a commercial entitlement, but it still limits what a session can install. A family is installed only when commands requests it and the widget allows it: with ai_commands.chartSettings off, settings.* stays unsupported; with study commands off, studies.apply is absent; with inspection off, the inspect reads are absent. Check sdk.capabilities().commands rather than assuming a requested family is present. Owners you pass in through owners are used as built, so the widget option does not apply to them.

FamilyCommandsBehavior
Drawingsdrawings.context, list, apply, groups, inspectDrawing batches with native receipts and Undo; group pages; exact-ID settings
Studiesstudies.context, list, apply, inspectBuilt-in study changes with expected revisions; exact-ID inputs and styles
Settingssettings.inspect, applyValidated chart and scale settings
Workspaceworkspace.context, applyPass workspace: widget.createWorkspaceCommands(options); you keep ownership

capabilities.query is installed whenever at least one of the drawing, study or settings families is; a session with commands: [] has none. Group and inspection reads appear only when the running chart supports them. Closing the session destroys the drawing, study and settings owners it created, never owners you passed in (see below); chart removal closes the session.

Built-in facade inputs and results have concrete types. Drawing and group pages allow up to 100 entries and study pages up to 20. Native parsers enforce operation limits and required fields. Capability discovery exposes supported fields and choices; do not assume every drawing setting is writable.

Mutations preserve native Undo and receipts. They do not save remotely unless you supply a persist hook (see extensions). There are no transactions across commands or services.

Keep one owner per chart

Each native family keeps its own lease, Undo history and persistence revision in one owner. Use one mutating owner per chart per family: two drawing owners on the same chart would hold separate leases and Undo stacks, so their edits could interleave unsafely. If you already hold an owner, for example one from createDrawingCommands or createDrawingDocument that saves your documents, pass it in:

await widget.loadAutomation();
const chart = widget.activeChart();
const drawings = chart.createDrawingCommands(binding); // your existing owner

const sdk = await chart.openAutomation({ owners: { drawings } });
const receipt = await sdk.drawings.apply({ operations: [{ action: 'create', type: 'horizontal_line', points: [{ price: 182.5 }] }] });
drawings.undo(receipt.operationId); // SDK changes share the owner's Undo history
sdk.close(); // `drawings` stays alive; you destroy it

owners accepts drawings, studies and settings. An adopted owner is used as-is and the session never destroys it. Families without an adopted owner are built and destroyed by the session as usual. When you also pass commands, every adopted family must be listed in it, or opening rejects with invalid_input. An adopted drawing owner also supplies the session's binding.

A second mutating session on the same chart must reuse the same owners rather than opening with fresh ones. Sessions that share an owner can run side by side and close independently.

Hosts that construct owners themselves can still call the lower-level factories (createDrawingCommands, createStudyCommands, createChartSettingsCommands) after widget.loadAutomation() and connect them with installNativeAutomationCommands(sdk, owners).

Model tools

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

const tools = createAutomationTools(sdk, {
  request: toolCallId => sdk.request({ requestId: toolCallId }), // the default
  imageResult: capture => uploadForMyProvider(capture.blob),     // enables capture_image
  use: [logCalls, confirmMutations],                             // middleware, outermost first
});
// Each tool: name, commandName, description, parameters, effect, concurrency, execute(toolCallId, input).

Translate each tool into your provider's format; the adapter has no model client, prompts, budgets or conversation store.

OptionPurpose
requestRequest envelope per call. Defaults to the call ID and the current chart.
describeReplaces a tool's description or parameters, e.g. to keep wording you have evaluated. Runs before include; return undefined to keep the derived tool. Input is still parsed by the command's own schema.
includeKeep only tools for which it returns true, e.g. tool => tool.effect === 'read'.
toolPrefixPrepended to derived names, e.g. chart_ for chart_drawings_apply.
toolNamesExact names by command, e.g. { 'drawings.apply': 'apply_chart_drawing_batch' }.
useMiddleware (call, next) => result for logging, confirmation, budgets or result shaping. Throw a ChartCommandError to refuse.
imageResultConverts a capture for your provider. Capture is advertised only when supplied.
errorResultShape of a failed call. Defaults to { error: code, details? }, where details names the rejected field path and a fixed reason; never the error message. null rethrows.

Tool names are snake_case: drawings.apply becomes drawings_apply and navigation.searchSymbols becomes navigation_search_symbols. The SDK ports are data_series, data_read, data_request_history and capture_image. Names must match [a-z][a-z0-9_-]{0,63}; a duplicate name rejects with operation_conflict.

Each tool reports its effect and concurrency. When a model asks for several calls in one step, run shared calls together and each exclusive call alone in call order. Reads default to shared; mutations and external calls default to exclusive.

Command examples are appended to that command's tool description as compact JSON lines (up to 2,000 characters), the same for local and remote sessions; commands without examples keep their description unchanged. sdk.instructions() joins the instructions of permitted commands for your system prompt. Tool lists are snapshots: rebuild them when sdk.capabilities().revision changes.

import { ChartCommandError, type AutomationToolMiddleware } from '@lumencharts/chart-automation/sdk';

const confirmMutations: AutomationToolMiddleware = async (call, next) => {
  if (call.tool.effect === 'mutation' && !(await askUser(`Allow ${call.tool.name}?`))) throw new ChartCommandError('cancelled');
  return next();
};

Policy and request lifetimes

Configure allowed effects (read, mutation, external) and optionally an exact command-name allowlist when opening a session. data_series follows the data.read permission. Defaults are eight concurrent requests, a 30-second deadline and 256 KiB JSON payloads. Finite ceilings also bound rows, series, fields and images; inspect capabilities().limits for effective values.

Omitted requests get a fresh ID and the current target. Explicit requests must use a unique ID for each in-flight operation; duplicates reject with operation_conflict. Requests accept an AbortSignal and an absolute deadline. Cancelled or timed-out handlers keep their concurrency slot until they settle, so repeated timeouts cannot start unlimited background work. Session methods always report failures by rejecting.

Policy is local capability filtering, not server authorization. Enforce asset access and hosted-service entitlements at your own server boundary. Model credentials belong outside the browser.

Add host adapters and extensions →

On this page