> For the complete documentation index, see [llms.txt](https://docs.appmixer.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appmixer.com/changelog/version-6/6/6.5/6.5.2.md).

# 6.5.2

2026-08-28

## New Features

#### AI Copilot <a href="#ai-copilot" id="ai-copilot"></a>

* **Copilot can be enabled for selected user scopes only** — `COPILOT_ENABLED_SCOPES` (`copilot.enabledScopes`) is a comma-separated allow-list of the user scopes Copilot is available to. It lives in the live, DB-backed Copilot configuration, so an admin changes it from the Backoffice without restarting a pod. Unset or empty means enabled for everyone, so the upgrade is a no-op until the list is set.
* **Prompt caching on the direct Anthropic provider path** — Copilot's stable prompt prefix (its tool definitions and roughly 20k tokens of system prompt) and its per-step conversation prefix are now marked with ephemeral `cache_control` breakpoints, so every agent step after the first reads them from the provider cache instead of re-processing them on each of up to `COPILOT_MAX_TURNS` steps. This cuts the input price of the cached prefix to about a tenth and substantially reduces time to first token. Controlled by `COPILOT_PROMPT_CACHING` (default `true`, live getter, Backoffice-editable), and cache effectiveness is logged per step and per turn. Direct Anthropic (and Anthropic-compatible) endpoints only — the Appmixer Cloud proxy path is unaffected.
* **Per-user AI context** — The user object gains an optional `aiContext` string, so embedded customers provisioning virtual users through the admin API can attach context for Copilot: the user's timezone, or facts about the group or property that a single virtual user represents. Copilot injects it into its system prompt as a fenced, semi-trusted **User AI Context** section, framed exactly like the instance-level `COPILOT_CUSTOM_CONTEXT` — it can inform answers but cannot override Copilot's core role, its safety rules or its flow-building rules. The field is strictly optional: a user without it produces a byte-identical prompt to before.
  * Setting it via `POST /user` requires the `admin` scope, because that route is reachable unauthenticated in a default deployment and the value reaches the system prompt. `PUT /users/{userId}` is already admin-scoped.
  * `USER_AI_CONTEXT_MAX_LENGTH` (default `8000`) caps the length. It is read at validation time, so it is tunable through the config API and can differ per tenant without a restart.
  * Read it back through `GET /user` or `GET /users/{userId}`.

## Bug Fixes

* **Whitespace is trimmed from configuration writes** — A configuration key or value set with surrounding whitespace through the Backoffice was stored verbatim, and the key was the damaging half: a padded key matches no entry in the configuration definitions, so the document was written under a type nothing ever reads and the setting was **silently ignored** while the Backoffice listed it as set. A padded value was forwarded to its consumer intact, where a trailing space on an API key comes back as an opaque `401`. `POST /config` now trims both key and value and `DELETE /config/{key}` trims the key param, before any validator sees them; a key that is blank once trimmed is rejected with a `400`. Already-stored values and environment variables are deliberately left alone.
* **A component type that cannot be resolved is now a validation error instead of a 500** — A flow containing a component whose type does not resolve — invented, malformed, or missing its action — crashed `GET /flows/{flowId}/validate`. That crash also silently disabled Copilot's save-and-validate loop, which is how flows with invalid variables could reach the Designer looking finished, and it broke the Designer's validation for such flows. The endpoint now reports each broken shape on the component itself with `descriptorPath: "type"`: an unresolvable four-segment type as `unknownComponentType` ("could not be found" — the type may simply not be loadable on that node), a malformed type with the expected `vendor.service.module.Component` format, and a three-segment type as `missingManifest`, which covers both selecting an action and replacing an invented type. Components downstream of the broken one degrade to ordinary invalid-variable errors rather than taking the request down.
* **Fixed log records being dropped by Elasticsearch when they carried an `_id` field** — Log extras are flattened into the top level of the log record, and Elasticsearch reserves leading-underscore keys there for its own metadata, so any log call passing `_id` had its whole document rejected with a 400 and never indexed. The MinIO GridFS migrator was doing exactly that in its `Skipping file with missing metadata` warning (which fires on every plugin start for interrupted uploads), so those warnings were lost. The field has been renamed, and log record creation now moves any reserved key under a prefixed name (`_id` → `extra_id`) instead of letting the record be dropped — this also protects log calls in customer-written system plugins.
* **Fixed variable modifiers being lost on key-value rows** — In the key-value style component fields, only one row's variable modifiers survived editing: the shared modifier map was bound through a single pass-through, so entering a variable with a modifier in one row could drop or overwrite the modifiers recorded for the others. A row that lost its modifier rendered as an unopenable red pill showing a bare identifier, and the loss was persisted into the flow. Each row now keeps its own modifiers through the whole edit chain, removing a row takes only its own targets out of the map, and opening an already-affected field no longer writes the damage in deeper.
* **The canvas now says when Copilot has locked the flow** — The Designer makes the whole canvas read-only while Copilot processes a request, but on a flow that already had steps nothing on screen said so: clicks and drags simply did nothing. Copilot now takes its place in the same badge slot at the top of the canvas that already announces a version preview or a running test, and clicking the badge opens the Copilot panel the run belongs to. The header's stage actions that a request disables — Test flow, Edit/Exit Draft, Publish Changes and Activate/Deactivate — now carry a tooltip explaining why, and the "add a step" chip goes read-only along with the stencil it opens.
* **The canvas is realigned after a Copilot turn that moved its steps** — Flows Copilot built arrived with crossing links and overlapping steps once they had several branches or more than a handful of components, because the server-side layout pass positions by connected pairs alone and is blind to which out-port a connection leaves from. The Designer now runs its own port-aware align command at the end of a turn, on exactly the turns where the backend relaid the flow — a turn that only changed configs, labels or ports leaves the user's own arrangement untouched. The realignment waits until the run has released the canvas and the flow has finished loading, is skipped after a **Stop** (where a backend write may still be in flight), and is held rather than lost while the browser tab is hidden.
* **The toolbar configuration now decides whether the built-in logs panel exists** — A host that leaves `'logs'` out of `config.options.toolbar` because it renders logs in its own UI could not actually turn the panel off: only the **View Logs** button honoured the setting, while the toolbar's chevron toggle, the auto-open on a running flow and the test run's "View logs" links all opened the same panel anyway. Availability is now decided in one place that every open goes through, and the test-run links are hidden rather than left pointing at a panel that will not open. Closing the panel is never gated, and the chevron stays visible while a panel is open so a panel opened before the configuration changed can still be closed.

{% hint style="warning" %}
A toolbar configured without a logs button now also suppresses `config.options.autoOpenLogs`. If your embedded application relies on the logs panel opening automatically, keep a logs button in `config.options.toolbar`.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.appmixer.com/changelog/version-6/6/6.5/6.5.2.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
