<!-- Public documentation export; not library implementation source. -->
# Native commands and model tools

## Open a session with native commands

```ts
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.

| Family | Commands | Behavior |
| --- | --- | --- |
| Drawings | `drawings.context`, `list`, `apply`, `groups`, `inspect` | Drawing batches with native receipts and Undo; group pages; exact-ID settings |
| Studies | `studies.context`, `list`, `apply`, `inspect` | Built-in study changes with expected revisions; exact-ID inputs and styles |
| Settings | `settings.inspect`, `apply` | Validated chart and scale settings |
| Workspace | `workspace.context`, `apply` | Pass `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](https://docs.lumencharts.com/charting-library/automation/extensions#durable-saves)). 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:

```ts
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

```ts
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.

| Option | Purpose |
| --- | --- |
| `request` | Request envelope per call. Defaults to the call ID and the current chart. |
| `describe` | Replaces 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. |
| `include` | Keep only tools for which it returns `true`, e.g. `tool => tool.effect === 'read'`. |
| `toolPrefix` | Prepended to derived names, e.g. `chart_` for `chart_drawings_apply`. |
| `toolNames` | Exact names by command, e.g. `{ 'drawings.apply': 'apply_chart_drawing_batch' }`. |
| `use` | Middleware `(call, next) => result` for logging, confirmation, budgets or result shaping. Throw a `ChartCommandError` to refuse. |
| `imageResult` | Converts a capture for your provider. Capture is advertised only when supplied. |
| `errorResult` | Shape 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.

```ts
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 →](https://docs.lumencharts.com/charting-library/automation/extensions)

---
Documentation page: https://docs.lumencharts.com/charting-library/automation/commands-and-tools
