mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
Connector/J parses a statement's SQL on every prepareStatement unless its per-connection parse cache is on, and that parse was the largest share of the control plane's Java CPU under load. The server and embedded MySQL pools now add cachePrepStmts=true, prepStmtCacheSize=512 and prepStmtCacheSqlLimit=8192 as connection properties. A connection property overrides the URL in Connector/J, so each setting is added only when neither the URL nor the Druid connection properties name it, ignoring case, percent-encoding and surrounding spaces. Nothing is added when either names useServerPrepStmts or useCursorFetch, since the cache would then hold statements open on the server. The server pool binds spring.datasource.druid inside its factory, before the defaults are added: @ConfigurationProperties bound it only after the factory returned, and the string form of connection-properties replaces every connection property.
332 lines
85 KiB
Markdown
332 lines
85 KiB
Markdown
# Managed Agent server configuration reference
|
|
|
|
[English](managed-agent-configuration-reference.md) | [简体中文](managed-agent-configuration-reference.zh-CN.md)
|
|
|
|
<!-- Generated by scripts/generate-managed-agent-configuration-reference.mjs; edit packages/managed-agent-server/configuration-descriptions.json instead. -->
|
|
|
|
Every setting of the Managed Agent control plane, `qwen-managed-agent-server`. The page is generated from the server build's configuration metadata, the packaged `application.yml` and `packages/managed-agent-server/configuration-descriptions.json`; edit that file, not this page, and regenerate:
|
|
|
|
```bash
|
|
mvn -f packages/managed-agent-server/pom.xml -DskipTests clean process-classes && node scripts/generate-managed-agent-configuration-reference.mjs
|
|
```
|
|
|
|
- **Variable** is the environment variable the packaged `application.yml` maps to the property, which `server.env` sets. A property without one is set in `config/application.yml`, which the launchers load when it exists; see the [deployment guide](managed-agent-reference-deployment.md).
|
|
- **Default** is what the packaged `application.yml` sets, or else the server's own default. *(empty)* is an empty value, *follows* names the property whose value is the default, and — means no value: the description says what applies then.
|
|
- A **duration** is a number with a unit, such as `500ms`, `30s`, `10m`, `24h` or `30d`. Always write the unit: a bare number does not mean the same unit everywhere.
|
|
- A **list** takes comma-separated values in a variable. A **YAML list** or **YAML map** can only be set in a configuration file.
|
|
|
|
## Database and listener
|
|
|
|
Spring settings the packaged `application.yml` maps to variables, and the listener port.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `server.address` | `QWEN_MANAGED_AGENT_SERVER_ADDRESS` | string | `127.0.0.1` | The address the public HTTP listener binds to. A non-loopback address needs `qwen.managed-agent.auth.mode=signed`; under `auto` or `open` mode startup refuses it unless `qwen.managed-agent.auth.allow-insecure-bind` is true. While the internal routes share this listener (no `qwen.managed-agent.internal-server.port`) and the Session Store or tool publication is on, a non-loopback address also needs `qwen.managed-agent.session-store.binding-key` unless `qwen.managed-agent.auth.allow-insecure-bind` is true. The `managed-local` profile refuses any non-loopback address. |
|
|
| `server.port` | `SERVER_PORT` | integer | `8080` | The port of the public listener the API and `/actuator/health` are served on. Spring Boot reads it from `SERVER_PORT`. |
|
|
| `spring.datasource.druid.max-active` | `QWEN_MANAGED_AGENT_DB_MAX_POOL_SIZE` | integer | `20` | How many connections the control plane's Druid database pool may hold at most. When all are busy, a request for a connection waits up to 30 seconds and then fails. Ignored under the `managed-local` profile, whose pool is fixed at 20. |
|
|
| `spring.datasource.password` | `SPRING_DATASOURCE_PASSWORD` | string | *(empty)* | The password of `spring.datasource.username`. A secret: keep it in a private environment file such as `server.env`, not on a command line. |
|
|
| `spring.datasource.url` | `SPRING_DATASOURCE_URL` | string | `jdbc:mysql://127.0.0.1:3306/qwen_managed_agent` | The JDBC URL of the MySQL 8 database that holds the control plane's state; Flyway applies the schema migrations to it at startup. The `managed-local` profile replaces it with a private H2 file database and refuses any other URL. For a `jdbc:mysql:` URL the server turns on Connector/J's cache of parsed statements: it adds `cachePrepStmts=true`, `prepStmtCacheSize=512` and `prepStmtCacheSqlLimit=8192` as connection properties, each only when neither this URL nor the Druid connection properties (`spring.datasource.druid.connect-properties` or `connection-properties`) name it, and none of them when either names `useServerPrepStmts` or `useCursorFetch`, with any value, since both can make Connector/J prepare statements on the server. `cachePrepStmts=false` in the URL turns the cache off. |
|
|
| `spring.datasource.username` | `SPRING_DATASOURCE_USERNAME` | string | `qwen` | The database user the control plane connects as. Besides rights on the control plane's database, it needs `SELECT` on `performance_schema.user_variables_by_thread`, which the preflight `--check` verifies. |
|
|
|
|
## `qwen.managed-agent`
|
|
|
|
Top-level settings of the Managed Agent server: the built-in agent revision, what stored AgentDefinitions may select, the Session model catalog, the trusted actor header and the service account, alongside the nested sections.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `agent-revision` | `QWEN_MANAGED_AGENT_REVISION` | string | `1` | The revision label of the built-in `qwen-code` agent, pinned on each Session that uses it; a request naming any other revision of `qwen-code` is refused. Must be 1 to 128 characters (startup refusal). |
|
|
| `child-relay.scan-delay` | — | duration | `2s` | How long the child result relay waits between passes; each pass drives child agent and workflow runs whose creation or result delivery to the parent Session is unfinished. Does nothing unless `qwen.managed-agent.runtime-broker.enabled` is true. Accepts a duration such as `2s`; a plain number is milliseconds. |
|
|
| `child-workspace.scan-delay` | — | duration | `2s` | How long the child Workspace pass waits between runs; each run resumes unfinished child Workspace Git steps (prepare, merge, apply, discard). Does nothing unless `qwen.managed-agent.runtime-broker.child-workspaces-enabled` is true. Accepts a duration such as `2s`; a plain number is milliseconds. |
|
|
| `definition-models` | `QWEN_MANAGED_AGENT_DEFINITION_MODELS` | list | *(empty)* | The model IDs a stored AgentDefinition may name in `model.id`, as a comma-separated list; a Session whose definition names any other model is refused at admission. Each ID should match a model provider route configured in the Harness. Empty admits only definitions without a model. |
|
|
| `definition-tool-profiles` | `QWEN_MANAGED_AGENT_DEFINITION_TOOL_PROFILES` | list | `hosted-workspace-files/1` | The hosted tool profiles a stored AgentDefinition may select in `tools`, as a comma-separated list (such as `hosted-workspace-files/1`, `hosted-workspace-shell/1` or `hosted-workspace-mcp/1`); a Session whose definition selects another profile is refused at admission. `hosted-workspace-team-lead/1` and Shell profiles other than `hosted-workspace-shell/1` are always refused, as is a Shell profile whose approval mode is `yolo`. Preflight checks that the Harness supports each listed profile. |
|
|
| `message-relay.scan-delay` | — | duration | `2s` | How long the Session message relay waits between passes; each pass moves pending messages between Sessions (handover, receipt, acceptance) and settles those that cannot be delivered. Skipped on a node without an available Hosted Harness. Accepts a duration such as `2s`; a plain number is milliseconds. |
|
|
| `model-catalog` | — | YAML list | *(empty)* | The models offered for Sessions of the built-in `qwen-code` agent, selectable at Session creation and changeable later by a Workspace operator. A list of objects with `model-id` (a model ID configured in the Harness; required, unique, at most 512 bytes) and `label` (display name, defaults to `model-id`, at most 512 characters); an invalid or duplicate entry is refused at startup. Set it in a YAML configuration file; there is no environment variable. Selection also needs `qwen.managed-agent.harness.workspace-files-enabled` and Harness support. |
|
|
| `model-config-base-urls` | — | YAML list | *(empty)* | Exact HTTP(S) base URLs permitted for complete Session model configurations, set as a YAML list. Empty disables admission of new configurations. Public creation accepts `model_config`; WebShell creation accepts `modelConfig`. Requires the Session Store, Harness capability `session-model-config/1` and a `SecretProtector` (provided by the enabled Runtime Broker and its credential key ring in the standard server). Model IDs and API keys need no Harness registration. See the [Session model configuration design](../design/managed-session-model-config.md). |
|
|
| `service-user` | `QWEN_MANAGED_AGENT_SERVICE_USER` | string | *(empty)* | The operating-system account the server runs as. Only the preflight check reads it: it confirms the account exists and checks that the configuration and credentials files are readable by that account rather than by the account running preflight. Empty checks access as the account running preflight. |
|
|
| `session-worktree.scan-delay` | — | duration | `1000` | How long the Session worktree pass waits between runs; each run resumes pending per-Session Git worktree steps and fails the initial Turns of Sessions whose worktree could not be prepared. Accepts a duration such as `1s`; a plain number is milliseconds. |
|
|
| `trusted-actor-header` | `QWEN_MANAGED_AGENT_TRUSTED_ACTOR_HEADER` | string | *(empty)* | The name of a request header (for example `X-Qwen-Actor-Id`) whose value is trusted as the caller's actor ID, together with `X-Qwen-Tenant-Id`, when no upstream principal is present. Used only in open authentication mode; combining it with signed mode is refused at startup. In open mode, `qwen.managed-agent.runtime-broker.local-directory-import-enabled` requires it. Never set it where untrusted clients can reach the server. Empty disables it. |
|
|
| `wake-recovery.scan-delay` | — | duration | `2s` | How long the wake recovery scan waits between passes; each pass finds up to eight Sessions holding committed inputs that no writer owns and reattaches them so their wake runs. Runs only with `qwen.managed-agent.session-store.enabled` and an available Hosted Harness. Accepts a duration such as `2s`; a plain number is milliseconds. |
|
|
|
|
## `qwen.managed-agent.artifacts`
|
|
|
|
Projection of Hosted Shell tool results into public tool results and downloadable stdout/stderr artifacts, and the limits on reading their content.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `enabled` | — | boolean | `false` | Whether tool results are projected into public tool results and artifacts, and whether the artifact read API is served. Reads answer not found unless `qwen.managed-agent.tool-publication.enabled` is also true, and they require an authenticated actor. Even while it is false, committed tool receipts are still recorded for projection, so turning it on later also projects the tool results recorded while it was off. Sessions created through the private CSI lane (the `csi-session` admin command) are the exception: their receipts are never recorded, so their tool results are never projected. |
|
|
| `max-concurrent-reads` | — | integer | `4` | How many artifact content downloads this server process serves at once; a download beyond that gets HTTP 429 `artifact_read_limit` with `Retry-After: 1`. Must be at least 1 (startup refusal). |
|
|
| `projection-interval` | — | duration | `1000` | How often the tool-result projection pass runs; each pass projects up to 8 pending tool results into public tool results and artifacts. A plain number is milliseconds; a value with a unit such as `1s` is also accepted. The pass does nothing unless `qwen.managed-agent.artifacts.enabled` is true. |
|
|
| `publish-original` | — | boolean | `false` | Whether projection publishes the sealed stdout and stderr streams of a tool result as downloadable artifacts, and whether an actor who can read the Session may download them. Requires `qwen.managed-agent.artifacts.enabled`. |
|
|
| `publish-preview` | — | boolean | `false` | Whether a projected tool result also carries a short text preview (at most the first 8 KiB of one stream, with ANSI and control characters removed) that every Session reader sees. Requires `qwen.managed-agent.artifacts.publish-original`. |
|
|
| `read-revalidation-interval` | — | duration | `5s` | How often an in-flight artifact download re-checks the caller's access (Workspace grant, read policy, Session state); `PT0S` checks before every chunk. After a revocation, what is written before the next check still reaches the client: up to one window's worth of a streaming download, or a whole Range response of at most 1 MiB, which is written in one piece after its last check. Once a check denies, nothing more is written. A bare number is seconds. |
|
|
| `read-timeout` | — | duration | `2m` | How long one artifact content download may take in total; the limit is checked between chunks: a download that exceeds it before its first chunk gets `503 artifact_unavailable`, and one already streaming is cut off mid-body. Whatever this value, the download also ends the same way when its stream from storage receives nothing for 50 seconds (the OSS client's default socket timeout, which no setting changes; a request to open the object that times out is first retried up to three times while this limit allows), or when the gap between two chunks lets its lease on the stored output lapse: the lease is renewed as chunks are read, so a gap of more than 90 seconds can end it and one of two minutes always does. Must be positive (startup refusal). A bare number is seconds. |
|
|
|
|
## `qwen.managed-agent.auth`
|
|
|
|
How the public API authenticates requests, open or HMAC-signed, and the startup guards that refuse unauthenticated or plaintext exposure beyond loopback.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `allow-insecure-bind` | `QWEN_MANAGED_AGENT_AUTH_ALLOW_INSECURE_BIND` | boolean | `false` | Whether to override the startup guards against unauthenticated or plaintext exposure: it lets `open` or `auto` mode serve a non-loopback `server.address`, the internal surface leave loopback without `qwen.managed-agent.session-store.binding-key`, and `qwen.managed-agent.harness.base-url` or `qwen.managed-agent.tool-publication.service-base-url` use plaintext `http` to a remote host. It does not lift the Harness pool TLS rule or the local directory import loopback rule. The preflight check warns while it is set. |
|
|
| `allowed-drift` | `QWEN_MANAGED_AGENT_AUTH_ALLOWED_DRIFT` | duration | `5m` | How far the `X-Qwen-Signature-Timestamp` of a signed request may differ from the server clock, in either direction, before the request is rejected with `401`. Used only in `signed` mode and compared in whole seconds. Startup refuses less than `1s`. A number without a unit is read as milliseconds. |
|
|
| `max-signed-body-bytes` | — | integer | `10485760` | The largest request body, in bytes, that `signed` mode buffers to verify its signature; a larger body is answered `413 payload_too_large`. Extension archive uploads have their own 100 MiB limit. Startup refuses a value below 1 in `signed` mode. |
|
|
| `mode` | `QWEN_MANAGED_AGENT_AUTH_MODE` | string | `auto` | How public API requests are authenticated, case-insensitive: `open` trusts the tenant header (and the optional trusted actor header), `signed` requires an HMAC-SHA256 signature keyed by `qwen.managed-agent.auth.signing-key`, and `auto` acts as `open` on a loopback `server.address` (an unset address counts as non-loopback). Startup refuses `auto` or `open` on any other address unless `qwen.managed-agent.auth.allow-insecure-bind` is true, and refuses other values. The `managed-local` profile requires `signed`. |
|
|
| `signing-key` | `QWEN_MANAGED_AGENT_AUTH_SIGNING_KEY` | string | *(empty)* | The secret HMAC-SHA256 key with which `signed` clients sign each public request (`X-Qwen-Signature`). Read only in `signed` mode, where startup refuses a key shorter than 32 bytes (UTF-8), a key equal to `qwen.managed-agent.session-store.binding-key`, and any `qwen.managed-agent.trusted-actor-header`. |
|
|
|
|
## `qwen.managed-agent.automation`
|
|
|
|
The automation runtime: the scanner that fires scheduled automation definitions, its lease, its slot window and its concurrency.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `concurrency` | — | integer | `4` | How many unfinished runs one automation definition with overlap policy `allow` may hold at once; a further due slot is recorded `skipped` with reason `count_limit`. Startup refuses a value below 1 when `qwen.managed-agent.automation.enabled` is true. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_AUTOMATION_ENABLED` | boolean | `true` | Whether the automation scanner runs and the automation create, update, retire and run routes are admitted; while off, those routes answer `409 automation_unavailable` and the read routes still answer. Those routes also need `qwen.managed-agent.session-store.enabled`. When on, startup refuses non-positive automation counts and durations. |
|
|
| `late-tolerance` | `QWEN_MANAGED_AGENT_AUTOMATION_LATE_TOLERANCE` | duration | `5m` | How late a due slot may be when the scanner sees it and still fire as scheduled. An older slot follows the definition's catch-up policy (`none`, `latest` or `bounded`) and is otherwise recorded missed. Startup refuses a non-positive value when automation is enabled. A plain number is milliseconds. |
|
|
| `lease` | `QWEN_MANAGED_AGENT_AUTOMATION_LEASE` | duration | `60s` | How long a scanner or a manual run holds an automation definition's lease, counted from its claim of that definition; once it lapses another node may claim the definition, and from that claim on the earlier holder's writes to it are refused. Startup refuses a non-positive value when automation is enabled. A plain number is milliseconds. |
|
|
| `lookback` | `QWEN_MANAGED_AGENT_AUTOMATION_LOOKBACK` | duration | `24h` | How far back the scanner derives a definition's due slots; slots older than this, or older than the definition's arming, are neither fired nor recorded, which bounds every catch-up. Startup refuses a non-positive value when automation is enabled. A plain number is milliseconds. |
|
|
| `max-slots-per-tick` | — | integer | `1000` | How many due slots the scanner keeps per definition in one tick; when the lookback window holds more, the oldest are cut and a warning is logged. The limit does not shorten the scan itself: the scanner still checks every minute from where its previous tick for the definition stopped, up to the whole lookback window. Startup refuses a value below 1 when `qwen.managed-agent.automation.enabled` is true. |
|
|
| `scan-delay` | `QWEN_MANAGED_AGENT_AUTOMATION_SCAN_DELAY` | duration | `10s` | How long the automation scanner waits between the end of one tick and the start of the next. Startup refuses a non-positive value when automation is enabled. A plain number is milliseconds. |
|
|
| `scanner-threads` | — | integer | `4` | How many definition rows one scanner tick works in parallel; the tick waits for all of them before the next tick starts. Because a lease is not counted from the tick's start (see `qwen.managed-agent.automation.lease`), a long tick hands out no already-expired lease. Startup refuses a value below 1 when `qwen.managed-agent.automation.enabled` is true. |
|
|
|
|
## `qwen.managed-agent.channels`
|
|
|
|
The trusted channel adapter surface on the internal listener and the lease on outbound delivery claims.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `claim-lease` | `QWEN_MANAGED_AGENT_CHANNELS_CLAIM_LEASE` | duration | `10m` | How long a channel adapter's claim on an outbound delivery stays valid without a receipt. Once it lapses, the reconcile pass records the delivery's outcome as unknown and never resends it automatically. A plain number is seconds. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_CHANNELS_ENABLED` | boolean | `false` | Whether the trusted channel adapter routes under `/internal/managed-channels/` (register, disconnect, inbound events, delivery claims, receipts and resends) are served. They authenticate by the tenant header alone, so startup refuses it unless `qwen.managed-agent.internal-server.port` sets a separate internal listener. |
|
|
| `scan-delay` | — | duration | `30s` | How long the channel reconcile pass waits between runs; each run settles up to 50 outbound delivery claims older than `qwen.managed-agent.channels.claim-lease` as unknown. Accepts a duration such as `30s`; a plain number is milliseconds. |
|
|
|
|
## `qwen.managed-agent.dispatch`
|
|
|
|
Leases, retry backoff and retry budgets for the work the control plane hands to the Hosted Harness, such as Turns, Session lifecycle operations and Action responses.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `lease-duration` | — | duration | `60s` | How long a node's lease on dispatched work (a Turn, Session lifecycle operation, Action response, task cancel, rename or context compression) lasts before another node may take it over; Turn, lifecycle operation, Action response and task cancel holders renew it while working, but a rename or context compression does not. Startup refuses a value below twice `qwen.managed-agent.dispatch.lease-renew-interval`. A plain number is seconds. |
|
|
| `lease-renew-interval` | — | duration | `20s` | How often a node renews its lease on a Turn it is running; Action response delivery renews at this interval or a third of `qwen.managed-agent.dispatch.lease-duration`, whichever is shorter. Startup refuses a value under one millisecond or above half the lease duration. A plain number is seconds. |
|
|
| `max-operation-retries` | — | integer | `10` | How many failed delivery attempts a Session lifecycle operation (such as close) or an Action response gets before it is recorded as failed; a close whose request already reached the Harness gets four times as many, and a close still waiting on a live journal writer, a Harness restart or the daemon is shown as blocked and keeps retrying instead. Startup refuses a negative value. |
|
|
| `max-post-admission-retries` | — | integer | `10` | How many failed attempts a Turn gets after its submission to the Hosted Harness was attempted; past it the Turn fails, normally with `hosted_harness_unavailable_after_admission`, because it may already have run. Startup refuses a negative value or one below `qwen.managed-agent.dispatch.max-pre-admission-retries`. |
|
|
| `max-pre-admission-retries` | — | integer | `5` | How many failed attempts a Turn gets before its submission to the Hosted Harness is attempted; past it the Turn fails, normally with `hosted_harness_unavailable`. It also bounds how often a Turn is deferred while Workspace files are unavailable. Startup refuses a negative value or one above `qwen.managed-agent.dispatch.max-post-admission-retries`. |
|
|
| `retry-initial-delay` | — | duration | `1s` | How long dispatch work waits before its first retry; each further retry doubles the wait up to `qwen.managed-agent.dispatch.retry-max-delay`. Used for Turns, Session lifecycle operations, Action responses, task cancels and renames. Startup refuses a zero or negative value. A plain number is seconds. |
|
|
| `retry-max-delay` | — | duration | `1m` | How long dispatch work waits at most between retries; the doubling backoff that starts at `qwen.managed-agent.dispatch.retry-initial-delay` stops growing here. Startup refuses a value below the initial delay. A plain number is seconds. |
|
|
| `scan-delay` | — | duration | `1s` | How long the dispatch recovery passes wait between runs. Each run re-drives due work: retryable or expired Turns, Session lifecycle operations, Action responses, task cancels, renames, context compressions, parked operations and owed Hosted cleanup. Accepts a duration such as `1s`; a plain number is milliseconds. |
|
|
|
|
## `qwen.managed-agent.event-transport`
|
|
|
|
The optional RocketMQ LiteTopic event transport that publishes committed Session events across nodes and runs the wake and materialization consumers.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `capability-probe-group` | — | string | `qwen-managed-journal-capability-probe` | The RocketMQ consumer group the startup LiteTopic capability probe subscribes in. Pre-create it as a LITE group bound to `qwen.managed-agent.event-transport.topic`; startup fails when the probe cannot subscribe. |
|
|
| `enabled` | — | boolean | `false` | Whether committed Session journal records and public events are also published to a RocketMQ LiteTopic broker, whose consumers carry wakes and materialization notices between nodes. Needs RocketMQ 5.5.0 or later with `enableLmq` and a pre-created LITE topic and groups; startup fails when the broker cannot serve them. The private CSI lane refuses work while it is on. |
|
|
| `endpoints` | — | string | *(empty)* | The RocketMQ proxy gRPC endpoint the event transport connects to, as `host:port` (for example `host:8081`). Required when `qwen.managed-agent.event-transport.enabled` is true; startup fails when the broker is unreachable or is not a gRPC (RocketMQ 5) proxy. |
|
|
| `owner-group` | — | string | `qwen-managed-session-owner` | The RocketMQ consumer group, shared by every node, in which each node subscribes to the LiteTopics of the Sessions it holds, so a Session's notices reach its owner. Pre-create it as a LITE group bound to `qwen.managed-agent.event-transport.topic`. |
|
|
| `owner-reconcile-interval` | — | duration | `1s` | How often a node re-aligns its owner-group subscriptions with the Sessions it holds, subscribing to newly held ones and dropping released ones. A plain number is seconds. |
|
|
| `topic` | — | string | *(empty)* | The parent RocketMQ topic under which each Session's LiteTopic and the wake bootstrap LiteTopic live. Required when `qwen.managed-agent.event-transport.enabled` is true. Pre-create it as a LITE topic (`message.type=LITE`); startup fails when it refuses a LiteTopic message. |
|
|
| `wake-bootstrap-group` | — | string | `qwen-managed-wake-bootstrap` | The RocketMQ consumer group, shared by every node, that consumes `qwen.managed-agent.event-transport.wake-bootstrap-lite-topic`, one member at a time. Pre-create it as a LITE group bound to `qwen.managed-agent.event-transport.topic`; startup fails when it cannot subscribe. |
|
|
| `wake-bootstrap-lite-topic` | — | string | `qwen-wake-bootstrap` | The LiteTopic under `qwen.managed-agent.event-transport.topic` that every `wake.requested` envelope is also sent to, so any node can learn of a wake that no node owns yet. Choose a name that cannot equal a Session id (a UUID). |
|
|
|
|
## `qwen.managed-agent.events`
|
|
|
|
Session event streams (SSE), batching of Harness output into Session events, message materialization and the replay floor.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `batch-interval` | — | duration | `75ms` | How long streamed text output from the Hosted Harness is buffered before it is written to the Session's events as one batch; a batch is written sooner on reaching `qwen.managed-agent.events.batch-max-events` or `qwen.managed-agent.events.batch-max-bytes`. Startup refuses a zero or negative value. A plain number is milliseconds. |
|
|
| `batch-max-bytes` | — | integer | `65536` | How many bytes of streamed text output one event batch may collect before it is written early, estimated as each delta's UTF-8 text plus 128 bytes. Startup refuses a zero or negative value. |
|
|
| `batch-max-events` | — | integer | `64` | How many streamed text deltas one event batch may collect before it is written early; the queue between the Harness stream reader and the writer also holds twice this many, at least 128. Startup refuses a zero or negative value. |
|
|
| `heartbeat-interval` | — | duration | `15s` | How often an idle Session event stream (SSE) sends a `keepalive` comment. A plain number is seconds. |
|
|
| `materialize-interval` | — | duration | `100ms` | How often the message materializer folds newly committed Session events into the message view that message and transcript queries read. A plain number is milliseconds. |
|
|
| `poll-interval` | — | duration | `5s` | How long an open Session event stream waits for an in-process event notification before it re-reads the Session's events from the database, catching anything the notification missed. It also bounds how long an idle stream takes to notice a revoked read grant. A plain number is seconds. |
|
|
| `read-grant-recheck-interval` | — | duration | `5s` | How often an open Session event stream re-verifies that its subscriber may still read the Session; `0s` checks before every event. A revoked grant stops delivery within this interval, and an idle stream closes within it plus `qwen.managed-agent.events.poll-interval`. A plain number is seconds. |
|
|
| `replay-floor-enabled` | `QWEN_MANAGED_AGENT_REPLAY_FLOOR_ENABLED` | boolean | `false` | Whether a scheduled pass raises each Session's replay floor up to what its message view already covers, never past an unfinished Turn. Event cursors below the floor then get `409 cursor_expired`, or one `agent.session.resync_required` frame on a stream. No event is deleted either way. The pass runs every `qwen.managed-agent.events.replay-floor-interval`. |
|
|
| `replay-floor-interval` | `QWEN_MANAGED_AGENT_REPLAY_FLOOR_INTERVAL` | duration | `60s` | How long the replay-floor pass waits between runs; each run works through every eligible Session, and it does nothing unless `qwen.managed-agent.events.replay-floor-enabled` is true. Accepts a duration such as `60s`; a plain number is milliseconds. |
|
|
| `stream-timeout` | — | duration | `30m` | How long one Session event stream (SSE) connection may stay open before the server ends it; the client must reconnect to keep receiving events. A plain number is seconds. |
|
|
|
|
## `qwen.managed-agent.extensions`
|
|
|
|
Publishing and managing Workspace extension packages, and which actors may do so.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `allowed-actors` | `QWEN_MANAGED_AGENT_EXTENSION_ALLOWED_ACTORS` | list | *(empty)* | The actor IDs allowed to publish extension packages, save their settings, and select or apply them for Sessions, as a comma-separated list; `*` allows every actor. The actor also needs Workspace OPERATOR access. Empty allows nobody. |
|
|
| `artifact-directory` | `QWEN_MANAGED_AGENT_EXTENSION_ARTIFACT_DIRECTORY` | string | *(empty)* | The directory that stores published extension package archives, in one private (`0700`) subdirectory per tenant and Workspace. Empty disables extension management. A symbolic link at the root or at a subdirectory makes archives unavailable. Replicas must share this directory. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_EXTENSION_PACKAGES_ENABLED` | boolean | `false` | Whether extension packages can be published and managed for Workspaces through the public extensions API. Management also needs `qwen.managed-agent.extensions.artifact-directory`, an actor in `qwen.managed-agent.extensions.allowed-actors` and Workspace OPERATOR access. With `qwen.managed-agent.runtime-broker.enabled`, startup refuses `qwen.managed-agent.managed-extensions.enabled` without it; otherwise extension execution simply stays off. |
|
|
|
|
## `qwen.managed-agent.harness`
|
|
|
|
The connection to the Hosted Harness (`qwen serve --profile hosted-harness`) that runs Sessions: its address and shared credentials, call timeouts, the approval policy, and which Workspace tools Sessions are created with.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `approval-mode` | `QWEN_MANAGED_AGENT_APPROVAL_MODE` | string | `yolo` | The approval mode Hosted Sessions start with, case-insensitive: `yolo`, `default` or `auto-edit`, plus `plan` and `auto` while Workspace files are off. Unbound built-in Sessions follow the current value; Workspace-bound Sessions pin it at creation. While `qwen.managed-agent.harness.workspace-files-enabled` is true, startup refuses any mode but the first three, and with `qwen.managed-agent.harness.workspace-shell-enabled` it refuses `yolo` too. Any other value fails the Harness connector, at startup for a single Harness. |
|
|
| `approval-timeout` | `QWEN_MANAGED_AGENT_APPROVAL_TIMEOUT` | duration | `10m` | How long a tool permission request waits for an answer before it expires and the tool call is refused. It is sent to the Harness when a Session is created. Startup refuses values outside `1s` to `24h`; a number without a unit is read as seconds. |
|
|
| `base-url` | `QWEN_MANAGED_AGENT_HARNESS_BASE_URL` | string | `http://127.0.0.1:4170` | The URL of the single Hosted Harness the control plane calls. Must be an absolute `http` or `https` URL without credentials, query or fragment while `qwen.managed-agent.harness.enabled` is true: a single Harness is refused at startup, and under `qwen.managed-agent.harness.pool.enabled` every pool member fails to join instead, so keep a valid value there even though the pool does not route by it. Startup refuses plaintext `http` to a non-loopback host unless `qwen.managed-agent.auth.allow-insecure-bind` is true. The `managed-local` profile requires a loopback `http` URL. |
|
|
| `capability-digest` | `QWEN_MANAGED_AGENT_CAPABILITY_DIGEST` | string | *(empty)* | The capability digest the Harness must advertise, written `sha256:` plus 64 lowercase hex characters and equal to the Harness's `QWEN_HOSTED_HARNESS_CAPABILITY_DIGEST`; a mismatch fails negotiation. Required while `qwen.managed-agent.harness.enabled` is true unless `qwen.managed-agent.harness.credentials-file` supplies it; setting both is refused at startup. |
|
|
| `connect-timeout` | — | duration | `5s` | How long the control plane waits to open a connection to a Hosted Harness, including Harness pool members. Must be positive; a number without a unit is read as seconds. |
|
|
| `credentials-file` | `QWEN_MANAGED_AGENT_HARNESS_CREDENTIALS_FILE` | string | *(empty)* | Path to the Harness's own environment file, read instead of setting the shared credentials here: it must set `QWEN_SERVER_TOKEN` and `QWEN_HOSTED_HARNESS_CAPABILITY_DIGEST`, and may set `QWEN_MANAGED_RUNTIME_BROKER_URL` and `QWEN_MANAGED_RUNTIME_BROKER_TOKEN` together. Read only while `qwen.managed-agent.harness.enabled` is true. Startup refuses it beside `qwen.managed-agent.harness.token` or `qwen.managed-agent.harness.capability-digest`, a file Broker token beside `qwen.managed-agent.runtime-broker.token`, an unreadable file, and any line systemd and a shell would read differently. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_HARNESS_ENABLED` | boolean | `false` | Whether the control plane runs Sessions on a Hosted Harness. When false, no Harness connector is created and Session execution fails as Harness disabled. When true, startup requires `qwen.managed-agent.session-store.enabled`, the Harness token and capability digest (directly or through `qwen.managed-agent.harness.credentials-file`), and for a single Harness a valid `qwen.managed-agent.harness.base-url`. The packaged configuration makes `qwen.managed-agent.session-store.enabled` follow it. |
|
|
| `heartbeat-interval` | — | duration | `30s` | How often the control plane sends a keepalive heartbeat for each attached Harness Session. `0` turns scheduled heartbeats off; negative values are refused. A number without a unit is read as seconds. |
|
|
| `load-timeout` | `QWEN_MANAGED_AGENT_HARNESS_LOAD_TIMEOUT` | duration | `120s` | How long a takeover load of a Harness Session may take, since it can settle parked Runtime executions; ordinary attach loads use `qwen.managed-agent.harness.request-timeout`. Must be positive while `qwen.managed-agent.harness.enabled` is true: a single Harness is refused at startup, and under `qwen.managed-agent.harness.pool.enabled` every pool member fails to join instead; a number without a unit is read as seconds. |
|
|
| `request-timeout` | — | duration | `30s` | How long a single ordinary call to the Hosted Harness may take, including attach loads that are not takeovers. Task cancellation attempts get at least four times this value, and never less than 5 minutes. Must be positive; a number without a unit is read as seconds. |
|
|
| `token` | `QWEN_MANAGED_AGENT_HARNESS_TOKEN` | string | *(empty)* | The bearer token the control plane sends to the Hosted Harness, equal to the Harness's `QWEN_SERVER_TOKEN`; a secret. Required while `qwen.managed-agent.harness.enabled` is true unless `qwen.managed-agent.harness.credentials-file` supplies it; setting both is refused at startup. The preflight check fails a value still starting with the template placeholder `replace-`. |
|
|
| `turn-deadline` | `QWEN_MANAGED_AGENT_HARNESS_TURN_DEADLINE` | duration | `30m` | How long an admitted Turn may run before the Harness settles it as a deadline failure, so a stalled model stream cannot hold a Session forever. It is sent with each Turn. Values outside `1ms` to about 24.8 days are refused while `qwen.managed-agent.harness.enabled` is true: a single Harness is refused at startup, and under `qwen.managed-agent.harness.pool.enabled` every pool member fails to join instead; a number without a unit is read as seconds. |
|
|
| `workspace-child-agents-enabled` | `QWEN_MANAGED_AGENT_WORKSPACE_CHILD_AGENTS_ENABLED` | boolean | `true` | Whether qualified Workspace Shell Sessions created while it is on may delegate work to public child agents: built-in `qwen-code` Sessions, and AgentDefinition Sessions too while managed extension execution is on. It takes effect only with `qwen.managed-agent.harness.workspace-shell-enabled`, `qwen.managed-agent.runtime-broker.durable-local-process`, `qwen.managed-agent.runtime-broker.provisioner=local-process`, `qwen.managed-agent.runtime-broker.bound-session-isolation-class=session` and a Harness that supports it; otherwise it stays off without an error. Setting it false stops further child launches. |
|
|
| `workspace-files-enabled` | `QWEN_MANAGED_AGENT_WORKSPACE_FILES_ENABLED` | boolean | `false` | Whether Workspace-bound Sessions get the Hosted Workspace file tools (`hosted-workspace-files/1`) and the Workspace file routes, which otherwise answer `409 workspace_files_disabled`. Startup requires the Harness, the Session Store and `qwen.managed-agent.runtime-broker.enabled`; a `local-process` Broker with `session` isolation and Workspace mounts, a creation root, verified Workspace recovery or SSH nodes (or an exclusive resident CSI setup); and approval mode `yolo`, `default` or `auto-edit`. External Runtime provisioners refuse it. |
|
|
| `workspace-shell-enabled` | `QWEN_MANAGED_AGENT_WORKSPACE_SHELL_ENABLED` | boolean | `false` | Whether built-in `qwen-code` Workspace Sessions are created with the `hosted-workspace-shell/1` profile: the file tools plus a foreground Shell. Startup requires `qwen.managed-agent.harness.workspace-files-enabled` and approval mode `default` or `auto-edit`, and refuses it with resident Workspaces or an external Runtime provisioner. Turning it off refuses fresh Turns on existing Shell Sessions with `409 workspace_unavailable`. |
|
|
|
|
## `qwen.managed-agent.harness.pool`
|
|
|
|
Placing Sessions on several Hosted Harness instances instead of the single `qwen.managed-agent.harness.base-url`, with static or Kubernetes discovery and mutual TLS to the members.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `discovery` | — | string | `static` | How the Harness pool finds its members: `static` reads `qwen.managed-agent.harness.pool.instances`; `kubernetes` watches the EndpointSlices of the Service named by `qwen.managed-agent.harness.pool.namespace`, `qwen.managed-agent.harness.pool.service-name` and `qwen.managed-agent.harness.pool.service-uid`. Startup refuses any other value, `kubernetes` together with static instances, and `kubernetes` without the mTLS key and trust stores. Membership is refreshed every 5 seconds. |
|
|
| `enabled` | — | boolean | `false` | Whether Sessions are placed on a pool of Hosted Harness instances, each Session staying on its member, instead of the single `qwen.managed-agent.harness.base-url`. Read only while `qwen.managed-agent.harness.enabled` is true. Startup requires `qwen.managed-agent.session-store.enabled`, `qwen.managed-agent.session-store.binding-key`, the Harness token and a `sha256:` capability digest, and refuses `qwen.managed-agent.runtime-broker.provisioner=kubernetes-workspace`. Members must advertise `harness-pool-owner/1` and `harness-instance-lifecycle/1` with identical capabilities. |
|
|
| `instances` | — | YAML list | *(empty)* | The static pool members, used when `qwen.managed-agent.harness.pool.discovery` is `static`; set in a configuration file (YAML). Each entry has `instance-id` (1 to 128 letters, digits, `.`, `_`, `:` or `-`, unique, equal to the instance ID that Harness reports) and `base-url` (an `http` or `https` origin without path, credentials, query or fragment). Startup refuses an empty list, more than 256 entries, and a non-loopback member without `https` and the pool's mTLS stores. |
|
|
| `key-store-file` | — | string | *(empty)* | Path to the PKCS12 key store with the client certificate and key the control plane presents to Harness pool members (mutual TLS). Must be set together with `qwen.managed-agent.harness.pool.trust-store-file`, or startup is refused. Required for `kubernetes` discovery and for any non-loopback member; with both stores empty, no client certificate is sent. |
|
|
| `key-store-password-file` | — | string | *(empty)* | Path to a file holding the password of `qwen.managed-agent.harness.pool.key-store-file`, also used as the key password. The file holds a secret. At most 4096 bytes; trailing whitespace is removed; empty means an empty password. Startup refuses a file that cannot be read or is too large. |
|
|
| `kubernetes-api-url` | — | string | `https://kubernetes.default.svc` | The Kubernetes API server origin that `kubernetes` discovery reads the Harness Service and its EndpointSlices from. Must be an `https` origin without path, credentials, query or fragment, or startup is refused. Read only when `qwen.managed-agent.harness.pool.discovery` is `kubernetes`. |
|
|
| `kubernetes-ca-file` | — | string | `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` | Path to the X.509 CA certificates (PEM or DER) used to verify the Kubernetes API server for `kubernetes` discovery. Startup refuses a file that cannot be read or holds no certificate. Read only when `qwen.managed-agent.harness.pool.discovery` is `kubernetes`. |
|
|
| `kubernetes-token-file` | — | string | `/var/run/secrets/kubernetes.io/serviceaccount/token` | Path to the bearer token file that `kubernetes` discovery sends to the Kubernetes API, normally the Pod's service account token. The file holds a secret and is read again for every request; it must be one non-empty line of at most 64 KiB, otherwise discovery fails and the pool places no further Sessions until it recovers. |
|
|
| `namespace` | — | string | *(empty)* | The Kubernetes namespace of the Harness Service and its EndpointSlices for `kubernetes` discovery. Must be a DNS label (lowercase letters, digits and `-`, at most 63 characters); startup refuses anything else when `qwen.managed-agent.harness.pool.discovery` is `kubernetes`. |
|
|
| `port-name` | — | string | `https` | The name of the TCP port in the Harness EndpointSlices that serves the Harness; `kubernetes` discovery calls each Pod at `https://<pod IP>:<port>` and uses the Pod UID as its instance ID. Must be a DNS label (startup refusal otherwise); a slice that lacks the port or lists it twice makes discovery fail. |
|
|
| `service-name` | — | string | *(empty)* | The name of the Kubernetes Service whose EndpointSlices list the Harness Pods for `kubernetes` discovery. Must be a DNS label; startup refuses anything else when `qwen.managed-agent.harness.pool.discovery` is `kubernetes`. |
|
|
| `service-uid` | — | string | *(empty)* | The `metadata.uid` of the Harness Service, which pins `kubernetes` discovery to that exact Service: a Service or EndpointSlice owner with another UID makes discovery fail and offers no members. Required, at most 256 characters, when `qwen.managed-agent.harness.pool.discovery` is `kubernetes`; startup refuses it empty. |
|
|
| `trust-store-file` | — | string | *(empty)* | Path to the PKCS12 trust store with the CA certificates used to verify Harness pool members' server certificates. Must be set together with `qwen.managed-agent.harness.pool.key-store-file`, or startup is refused; that property says when the stores are required. |
|
|
| `trust-store-password-file` | — | string | *(empty)* | Path to a file holding the password of `qwen.managed-agent.harness.pool.trust-store-file`. The file holds a secret. At most 4096 bytes; trailing whitespace is removed; empty means an empty password. Startup refuses a file that cannot be read or is too large. |
|
|
|
|
## `qwen.managed-agent.internal-server`
|
|
|
|
An optional separate listener for the internal routes (`/internal/**`), such as the Session Store the Harness calls, so they do not share the public listener.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `address` | `QWEN_MANAGED_AGENT_INTERNAL_SERVER_ADDRESS` | string | `127.0.0.1` | The address the separate internal listener binds when `qwen.managed-agent.internal-server.port` is set; empty means `127.0.0.1`. Startup refuses an address that does not resolve, and a non-loopback address without `qwen.managed-agent.session-store.binding-key` unless `qwen.managed-agent.auth.allow-insecure-bind`. The listener is always plaintext, and the server warns when it leaves loopback. The `managed-local` profile requires a loopback address. |
|
|
| `port` | `QWEN_MANAGED_AGENT_INTERNAL_SERVER_PORT` | integer | `0` | The port of a separate listener for the internal routes (`/internal/**`, including the Session Store); `0` or less serves them on the public listener. When set, each listener answers 404 for the other's routes. Startup refuses a port equal to `server.port`, and `qwen.managed-agent.channels.enabled` requires a port. The listener never inherits `server.ssl`. |
|
|
|
|
## `qwen.managed-agent.managed-extensions`
|
|
|
|
Running the processes of selected extension packages inside Workspace Runtime workers under the managed extension execution profile.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `cache-directory` | `QWEN_MANAGED_AGENT_EXTENSION_CACHE_DIRECTORY` | string | *(empty)* | The absolute directory where Runtime workers cache the extension packages they run; keep it private and outside every Workspace. Required when `qwen.managed-agent.managed-extensions.enabled` is true: a relative or empty path is refused at startup when the Runtime Broker uses local-process or SSH workers. |
|
|
| `cgroup-root` | `QWEN_MANAGED_AGENT_EXTENSION_CGROUP_ROOT` | string | *(empty)* | The absolute path of a writable, delegated cgroup v2 subtree under which Linux Runtime workers contain extension processes. Required for Linux workers when `qwen.managed-agent.managed-extensions.enabled` is true (a Runtime launch fails without it); must be empty in `developer-process-group` mode. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_EXTENSION_EXECUTION_ENABLED` | boolean | `false` | Whether Workspace Runtimes run with the managed extension execution profile, which lets selected extension packages run their processes (such as Hooks and MCP servers) in Runtime workers. Requires `qwen.managed-agent.extensions.enabled` (startup refusal) and `qwen.managed-agent.managed-extensions.cache-directory`, plus `qwen.managed-agent.managed-extensions.cgroup-root` on Linux. |
|
|
| `mode` | `QWEN_MANAGED_AGENT_EXTENSION_EXECUTION_MODE` | string | `linux-cgroup` | The extension execution mode: `linux-cgroup` contains extension processes in a delegated cgroup v2 subtree, and `developer-process-group` is a weaker process-group mode for native macOS development. Linux workers always use `linux-cgroup`; a macOS worker is refused unless this is `developer-process-group`. |
|
|
|
|
## `qwen.managed-agent.runtime-broker`
|
|
|
|
The embedded Runtime Broker: its private HTTP listener for the Hosted Harness, the provisioner that places and recovers the Runtime workers that run Hosted tools, their Workspace mounts and isolation, and the keys that encrypt the Runtime credentials it persists.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `allow-non-loopback` | `QWEN_MANAGED_AGENT_RUNTIME_BROKER_ALLOW_NON_LOOPBACK` | boolean | `false` | Whether the embedded Runtime Broker may bind a non-loopback address in `qwen.managed-agent.runtime-broker.host`, such as `0.0.0.0`; without it, startup refuses such an address. The listener serves one global bearer token over plaintext HTTP, with no per-tenant authorization, so enable it only behind a layer that terminates TLS and authorizes callers: restricting the network alone still sends the token in clear text, and whoever reads it can drive every execution the Broker admits. The `managed-local` profile refuses a non-loopback host regardless. |
|
|
| `bound-session-isolation-class` | — | string | `session` | How Runtime workers are shared among Sessions bound to a mounted local Workspace: `session` gives each Session its own worker, `workspace` lets the Sessions of one Workspace share one. Startup refuses other values. `workspace` requires the `local-process` provisioner with `qwen.managed-agent.runtime-broker.durable-local-process` and cannot combine with `qwen.managed-agent.runtime-broker.child-workspaces-enabled`; Session worktrees and public child agents need `session`. SSH-bound Sessions always use `session`. |
|
|
| `child-snapshots-enabled` | — | boolean | `false` | Whether Hosted Sessions may also launch read-only snapshot child agents, which read a frozen, always-discarded copy of the parent's Workspace through a tool profile without writing tools. Requires `qwen.managed-agent.runtime-broker.child-workspaces-enabled`; startup refuses it alone, and also refuses it with an external provisioner. |
|
|
| `child-workspace-git` | — | string | `git` | The Git executable that child Workspace and Session worktree steps run; a bare name is looked up on the server's `PATH`. It must be Git 2.40 or later. With `qwen.managed-agent.runtime-broker.child-workspaces-enabled`, startup probes its version and refuses an older Git. |
|
|
| `child-workspace-git-timeout` | — | duration | `2m` | How long each Git command of a child Workspace or Session worktree step may run before it is killed. A suffix-less number binds as milliseconds, so write the unit. With `qwen.managed-agent.runtime-broker.child-workspaces-enabled`, startup refuses values outside 1s to 1h. |
|
|
| `child-workspaces-enabled` | — | boolean | `false` | Whether Hosted Sessions may run child agents in isolated child Workspaces: Git worktrees inside the parent's storage, merged back or discarded after the child Session closes. Startup requires `qwen.managed-agent.runtime-broker.enabled`, the `local-process` provisioner, `session` in `qwen.managed-agent.runtime-broker.isolation-class`, `qwen.managed-agent.runtime-broker.durable-local-process`, `qwen.managed-agent.runtime-broker.workspace-mounts` or `qwen.managed-agent.runtime-broker.workspace-creation-root`, Git 2.40 or later, a UTF-8 locale and a non-Windows host, and refuses `workspace` in `qwen.managed-agent.runtime-broker.bound-session-isolation-class`. |
|
|
| `credential-key` | `QWEN_MANAGED_AGENT_RUNTIME_CREDENTIAL_KEY` | string | *(empty)* | The active Runtime credential key: a base64-encoded 32-byte AES-256-GCM key that encrypts the Runtime provision seeds, worker lease tokens and managed extension settings stored in the database. A secret. Required when `qwen.managed-agent.runtime-broker.enabled` is on; startup refuses an empty value, invalid base64 or a length other than 32 bytes. Generate one with `openssl rand -base64 32`. |
|
|
| `credential-key-id` | `QWEN_MANAGED_AGENT_RUNTIME_CREDENTIAL_KEY_ID` | string | *(empty)* | The ID of the active Runtime credential key, stored beside every ciphertext it writes so that reads pick the matching key. Not a secret. Required when `qwen.managed-agent.runtime-broker.enabled` is on; startup refuses an empty value, one over 512 characters, or an ID also listed in `qwen.managed-agent.runtime-broker.previous-credential-keys`. Changing the ID and key is a rotation: keep the old pair in that map. |
|
|
| `durable-local-process` | `QWEN_MANAGED_AGENT_RUNTIME_DURABLE_LOCAL_PROCESS` | boolean | `true` | Whether the `local-process` provisioner registers every Runtime worker launch in `qwen.managed-agent.runtime-broker.state-directory` so that a restarted Broker adopts the same live worker; when off, workers stop with the Broker. Needs Linux, or macOS with `qwen.managed-agent.runtime-broker.trusted-local-reboot-recovery` off, and a state directory outside every Workspace root; startup refuses otherwise. Trusted reboot recovery, child Workspaces, Workspace creation, local directory import and `workspace` bound-Session isolation require it. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_RUNTIME_BROKER_ENABLED` | boolean | `false` | Whether the control plane runs the embedded Runtime Broker, which places the Runtime workers that execute Hosted tools and serves the Hosted Harness on `qwen.managed-agent.runtime-broker.host` and `qwen.managed-agent.runtime-broker.port`. When on, startup requires `qwen.managed-agent.runtime-broker.token`, `qwen.managed-agent.runtime-broker.credential-key-id`, `qwen.managed-agent.runtime-broker.credential-key`, `qwen.managed-agent.runtime-broker.workspace-cwd` and `qwen.managed-agent.harness.capability-digest`. Hosted Workspace files and child Workspaces require it. |
|
|
| `environment` | — | YAML map | *(empty)* | Extra environment variables for Runtime workers, as a map from variable name to value, set in a configuration file (YAML). No provisioner passes them on: startup refuses a non-empty map with the `local-process` provisioner, and the other provisioners ignore it. |
|
|
| `external-provider-id` | `QWEN_MANAGED_AGENT_EXTERNAL_RUNTIME_PROVIDER_ID` | string | `external` | The provider ID that the `external-scratch` and `external-workspace` provisioners record in every Runtime handle and digest into its identity. With either provisioner, startup refuses an empty value or one over 512 characters. Set it once before the first Session: changing it later invalidates every existing external binding. |
|
|
| `external-provider-token` | `QWEN_MANAGED_AGENT_EXTERNAL_RUNTIME_PROVIDER_TOKEN` | string | *(empty)* | The bearer token the Broker sends to the external Runtime provider's `provision` and `observe` routes. A secret. With an external provisioner, startup refuses a value that is not 16 to 4096 characters of letters, digits and `._~+/=-`, or that starts with `replace-`, the shipped template placeholder. |
|
|
| `external-provider-url` | `QWEN_MANAGED_AGENT_EXTERNAL_RUNTIME_PROVIDER_URL` | string | *(empty)* | The base URL of the operator-run external Runtime provider; the Broker POSTs to its `provision` and `observe` routes below this path and follows no redirects. Required with the `external-scratch` and `external-workspace` provisioners: startup refuses anything but an HTTP(S) URL with a host and no credentials, query or fragment. Use HTTPS outside a trusted network. |
|
|
| `external-request-timeout` | `QWEN_MANAGED_AGENT_EXTERNAL_RUNTIME_REQUEST_TIMEOUT` | duration | `30s` | How long one HTTP call to the external Runtime provider may take before it fails; establishing the connection is separately bounded at 5 seconds. A suffix-less number binds as seconds. Read only with an external provisioner, where startup refuses a value under 1ms. |
|
|
| `external-startup-timeout` | `QWEN_MANAGED_AGENT_EXTERNAL_RUNTIME_STARTUP_TIMEOUT` | duration | `2m` | How long the Broker keeps polling the external provider's `observe` route after `provision` for the provisioned worker to report ready; when it lapses, the placement fails with the retryable `runtime_external_unavailable`. A suffix-less number binds as seconds. Read only with an external provisioner, where startup refuses a value under 1ms. |
|
|
| `host` | `QWEN_MANAGED_AGENT_RUNTIME_BROKER_HOST` | string | `127.0.0.1` | The address the embedded Runtime Broker's HTTP listener binds; the Hosted Harness reaches it through its own `QWEN_MANAGED_RUNTIME_BROKER_URL`. A non-loopback address, including `0.0.0.0`, requires `qwen.managed-agent.runtime-broker.allow-non-loopback`, and the `managed-local` profile refuses one regardless. Preflight compares the Broker URL in the Harness credentials file with this listener. |
|
|
| `isolation-class` | `QWEN_MANAGED_AGENT_RUNTIME_ISOLATION` | string | `session` | How the Broker shares Runtime workers among Sessions with no Workspace binding: `session` gives each Hosted Session its own worker, `workspace` shares one across the configured Workspace. Startup refuses `workspace` with Hosted Workspace files on `local-process`, child Workspaces or an external provisioner, and refuses `session` with the `static` or `kubernetes-workspace` provisioner. Workspace-bound Sessions use `qwen.managed-agent.runtime-broker.bound-session-isolation-class` instead. |
|
|
| `local-directory-import-enabled` | `QWEN_MANAGED_AGENT_LOCAL_DIRECTORY_IMPORT_ENABLED` | boolean | `false` | Whether WebShell may import an existing directory on this host as a Workspace, registering its parent as storage and granting the importing actor OWNER access. For a trusted single-user host: startup requires a loopback `server.address` with signed authentication or `qwen.managed-agent.trusted-actor-header`, plus `qwen.managed-agent.harness.workspace-files-enabled`, `qwen.managed-agent.runtime-broker.durable-local-process` and `qwen.managed-agent.runtime-broker.verified-workspace-recovery-enabled`. |
|
|
| `node-executable` | `QWEN_MANAGED_AGENT_NODE_EXECUTABLE` | string | *(empty)* | The path of the Node.js executable that runs the local Runtime worker (`qwen.managed-agent.runtime-broker.worker-entry`) and the helper processes for local Workspace file reads and uploads. Required with the `local-process` provisioner; startup refuses it empty. Preflight checks that it is executable. |
|
|
| `operator-recovery-enabled` | `QWEN_MANAGED_AGENT_RUNTIME_OPERATOR_RECOVERY_ENABLED` | boolean | `false` | Whether the offline operator-recovery command (`bin/qwen-managed-agent-operator-recovery`) may run its `inspect`, `prepare` and `complete` steps for a Hosted Shell capture that kept a Workspace lease. Set it for that maintenance process: the command refuses to run unless it is on with `qwen.managed-agent.runtime-broker.durable-local-process`, the `local-process` provisioner and `qwen.managed-agent.runtime-broker.state-directory`. The server refuses it at startup with an external provisioner. |
|
|
| `port` | `QWEN_MANAGED_AGENT_RUNTIME_BROKER_PORT` | integer | `4182` | The TCP port of the embedded Runtime Broker's HTTP listener; the Hosted Harness's `QWEN_MANAGED_RUNTIME_BROKER_URL` must reach it, directly on a loopback address or through the TLS-terminating proxy in front of a non-loopback bind. Startup fails when the listener cannot bind it. Preflight checks that the port is free, or listening with `--online`, and compares it with the Broker URL in the Harness credentials file. |
|
|
| `previous-credential-keys` | — | YAML map | *(empty)* | Earlier Runtime credential keys kept after a rotation, as a map from key ID to base64-encoded 32-byte key, so rows encrypted under them stay readable; writes use only the active key. Secrets. Set it in a configuration file (YAML), each ID in brackets, such as `'[old-v1]': <key>`; environment variables cannot supply it. Startup refuses a key that is not 32 bytes or an ID equal to `qwen.managed-agent.runtime-broker.credential-key-id`. |
|
|
| `provider-options` | — | YAML map | `{}` | Provider-specific string settings passed to the selected Runtime factory, configured as a YAML map. Their meaning and validation belong to that provider; built-in backends continue to use their existing settings. Defaults to an empty map. |
|
|
| `provisioner` | `QWEN_MANAGED_AGENT_RUNTIME_PROVISIONER` | string | `local-process` | The installed factory kind that places Runtime workers: `local-process` (local Node.js workers), `ssh-process` (registered SSH Workspaces), `static` (a preconfigured worker), `external-scratch` or `external-workspace` (an operator-run HTTP provider), or `kubernetes-workspace` (resident CSI Workspaces). A trusted additional provider may register its own kind. With the Broker enabled, missing or duplicate kinds fail before resources are created; `kubernetes` remains reserved and rejected. Embedding hosts must explicitly include the selected backend artifact. |
|
|
| `resident-kubernetes-api-url` | — | string | *(empty)* | The HTTPS origin of the Kubernetes API server that the `kubernetes-workspace` provisioner calls for `qwen.managed-agent.runtime-broker.resident-workspaces`, together with `qwen.managed-agent.runtime-broker.resident-kubernetes-token-file` and `qwen.managed-agent.runtime-broker.resident-kubernetes-ca-file`. Startup refuses resident Workspaces without it, and refuses a URL that is not `https` or has a path, credentials, query or fragment. The resident-retirement maintenance command reads it too. |
|
|
| `resident-kubernetes-ca-file` | — | string | *(empty)* | Path to a PEM or DER file of X.509 CA certificates that the server trusts, instead of the JVM defaults, for TLS to the Kubernetes API named by `qwen.managed-agent.runtime-broker.resident-kubernetes-api-url`. Required when `qwen.managed-agent.runtime-broker.resident-workspaces` is set; an unreadable file or one without certificates fails startup. The `resident-retirement` admin command reads it too. |
|
|
| `resident-kubernetes-token-file` | — | string | *(empty)* | Path to a file holding the bearer token the server sends to the Kubernetes API to manage resident Workspace Pods. The file holds a secret; it is re-read on every request, so the token can be rotated in place, and it must contain at most 16 KiB of letters, digits and `._~-`. Required when `qwen.managed-agent.runtime-broker.resident-workspaces` is set; the `resident-retirement` admin command reads it too. |
|
|
| `resident-workspaces` | — | YAML list | *(empty)* | The Workspaces served by dedicated resident Kubernetes Pods on CSI storage, set in a configuration file (YAML) as a list. Each entry has `workspace-id`, `workspace-generation` (1 or more), `registration` (the registered CSI storage: `tenant-id`, `storage-id`, `cluster-domain`, `namespace`, `pvc-name`, `pvc-uid`, `pv-name`, `pv-uid`, `driver`, `volume-handle`, `backend-domain`, `disk-serial`, `mount-root`, `revision`), `protection` (`namespace-uid`, `policy-name`, `policy-uid`, `policy-generation`, `binding-name`, `binding-uid`, `binding-generation`), `image` (pinned as `name@sha256:<64 hex>`), `command` (1 to 32 arguments: the executable and CLI path) and `artifacts` (up to 48 ConfigMaps, each with `config-map-name`, `uid` and `sha256`). A non-empty list needs the `kubernetes-workspace` provisioner with its three `resident-kubernetes-*` settings, `workspace` isolation and Workspace files, and refuses Workspace mounts, SSH nodes, trusted reboot or verified Workspace recovery, child Workspaces and Workspace Shell. Each tenant Workspace and each volume may appear once, and each `registration` must match a registered CSI storage record. |
|
|
| `session-create-warm` | — | boolean | `false` | Whether creating a Workspace-bound Session without initial input starts its Runtime worker right away instead of at the first Turn. Requires `qwen.managed-agent.runtime-broker.bound-session-isolation-class` set to `workspace` and no `qwen.managed-agent.runtime-broker.ssh.nodes`; startup refuses it otherwise and with external provisioners. Has no effect while Workspace files are unavailable. |
|
|
| `session-worktrees-enabled` | — | boolean | `false` | Whether a Workspace Session may be created in its own Git worktree of the Workspace repository, checked out from an optional local base ref under `.qwen-managed-worktrees` on a new `worktree-managed-<id>` branch. Takes effect only with `qwen.managed-agent.runtime-broker.enabled`, `qwen.managed-agent.runtime-broker.durable-local-process`, the `local-process` provisioner and `qwen.managed-agent.runtime-broker.bound-session-isolation-class` set to `session`, on a non-Windows host whose JVM uses UTF-8 file names; otherwise worktree requests are refused with `worktree_unsupported`. |
|
|
| `state-directory` | `QWEN_MANAGED_AGENT_RUNTIME_STATE_DIRECTORY` | string | *(empty)* | The directory where the local-process Broker keeps worker registrations and recovery records; workers also run with it as their working directory. Required when `qwen.managed-agent.runtime-broker.provisioner` is `local-process`. With `qwen.managed-agent.runtime-broker.durable-local-process` it is created if missing, provided its parent exists, and must be owned by the server account with mode `0700`, have no symlinks in its path, and lie outside `qwen.managed-agent.runtime-broker.workspace-cwd`, `qwen.managed-agent.runtime-broker.workspace-creation-root` and every `qwen.managed-agent.runtime-broker.workspace-mounts` root; startup refuses otherwise. A relative path resolves against the server's working directory. |
|
|
| `static-endpoint` | `QWEN_MANAGED_AGENT_STATIC_RUNTIME_ENDPOINT` | string | *(empty)* | The HTTP(S) origin of the already-running Runtime worker that the `static` provisioner hands to every Session; an origin only, without path, credentials, query or fragment. Required, with `qwen.managed-agent.runtime-broker.static-token`, when `qwen.managed-agent.runtime-broker.provisioner` is `static`, which also requires `qwen.managed-agent.runtime-broker.isolation-class` set to `workspace` and `qwen.managed-agent.runtime-broker.trusted-local-reboot-recovery` set to false. |
|
|
| `static-epoch` | — | integer | `1` | The lease epoch of the static Runtime worker; the Broker sends it with each request and the worker's attestation must report the same value. Startup refuses a negative value. Read only when `qwen.managed-agent.runtime-broker.provisioner` is `static`. |
|
|
| `static-lease-id` | — | string | `standalone-lease` | The lease ID of the static Runtime worker; the Broker sends it with each request and the worker's attestation must report the same value. A non-empty string of at most 512 characters. Read only when `qwen.managed-agent.runtime-broker.provisioner` is `static`. |
|
|
| `static-runtime-instance-id` | — | string | `standalone-runtime` | The Runtime instance ID of the static Runtime worker's lease; the worker's attestation must report the same value. A non-empty string of at most 512 characters. Read only when `qwen.managed-agent.runtime-broker.provisioner` is `static`. |
|
|
| `static-token` | `QWEN_MANAGED_AGENT_STATIC_RUNTIME_TOKEN` | string | *(empty)* | The bearer token the Broker presents to the static Runtime worker. A secret; saved bindings store it encrypted with the Runtime credential key (`qwen.managed-agent.runtime-broker.credential-key`). Required when `qwen.managed-agent.runtime-broker.provisioner` is `static`; at most 512 characters. |
|
|
| `token` | `QWEN_MANAGED_AGENT_RUNTIME_BROKER_TOKEN` | string | *(empty)* | The bearer token the Hosted Harness presents to the embedded Runtime Broker's private listener; it also authorizes the loopback-only external storage registration endpoint. A secret. Required when `qwen.managed-agent.runtime-broker.enabled` is true; at most 512 characters. It can come from `qwen.managed-agent.harness.credentials-file` (`QWEN_MANAGED_RUNTIME_BROKER_TOKEN`) instead; setting it in both places is refused at startup. |
|
|
| `trusted-local-reboot-recovery` | `QWEN_MANAGED_AGENT_RUNTIME_TRUSTED_LOCAL_REBOOT_RECOVERY` | boolean | `true` | Whether, after a whole-host reboot on Linux, the Broker treats the changed kernel boot ID as proof that the original local workers stopped, and clears the holders of their saved Runtime bindings once every execution is terminal. It scans 8 saved bindings every 5 seconds and never starts a replacement worker or replays an execution. Requires `qwen.managed-agent.runtime-broker.durable-local-process` and the `local-process` provisioner; startup refuses it otherwise, on macOS and with resident Workspaces. |
|
|
| `v3-result-window` | `QWEN_MANAGED_AGENT_RUNTIME_BROKER_V3_RESULT_WINDOW` | duration | `30m` | How long the Runtime Broker keeps waiting for the worker's result of a dispatched Shell or Monitor execution that publishes its output (Tool v3, with `qwen.managed-agent.tool-publication.enabled`) before marking it `UNKNOWN`; a value shorter than the longest such call turns that call into `UNKNOWN`. Other tool executions do not use this window. A value above `30m` buys nothing on the shipped path: the Hosted Harness stops waiting for a Tool v3 execution after its own fixed 30 minutes. A suffix-less number binds as seconds. Startup refuses a value below `1s`. |
|
|
| `verified-workspace-recovery-enabled` | `QWEN_MANAGED_AGENT_RUNTIME_VERIFIED_WORKSPACE_RECOVERY_ENABLED` | boolean | `false` | Whether LOCAL Workspace execution is gated on a verified physical storage registration: before tools, file access or child Git run, the server checks that the Workspace root still matches its registered identity and marker, and otherwise refuses with `409 workspace_unavailable`. Required by `qwen.managed-agent.runtime-broker.workspace-creation-root` and `qwen.managed-agent.runtime-broker.local-directory-import-enabled`; without `qwen.managed-agent.runtime-broker.workspace-mounts` it also satisfies the Workspace source that `qwen.managed-agent.harness.workspace-files-enabled` needs. Startup refuses it with external provisioners and resident Workspaces. |
|
|
| `worker-entry` | `QWEN_MANAGED_AGENT_RUNTIME_WORKER_ENTRY` | string | *(empty)* | Path to the built Qwen Code CLI bundle (for example `dist/cli.js`) that `qwen.managed-agent.runtime-broker.node-executable` runs with `managed-runtime-worker` to start local-process workers; LOCAL Workspace file-reference checks and uploads also run through it. Required when `qwen.managed-agent.runtime-broker.provisioner` is `local-process`; a relative path resolves against the server's working directory. |
|
|
| `workspace-creation-root` | `QWEN_MANAGED_AGENT_WORKSPACE_CREATION_ROOT` | string | *(empty)* | An existing canonical directory the server account can write, under which it creates new empty Workspaces in per-tenant subdirectories when users start a Workspace from scratch; empty disables Workspace creation. It must not overlap any `qwen.managed-agent.runtime-broker.workspace-mounts` root, `qwen.managed-agent.runtime-broker.state-directory` or `qwen.managed-agent.runtime-broker.workspace-cwd`, and requires `qwen.managed-agent.harness.workspace-files-enabled`, `qwen.managed-agent.runtime-broker.durable-local-process` and `qwen.managed-agent.runtime-broker.verified-workspace-recovery-enabled`; startup refuses otherwise and with external provisioners. Any authenticated tenant actor can then allocate storage there and becomes its owner. |
|
|
| `workspace-cwd` | `QWEN_MANAGED_AGENT_WORKSPACE_CWD` | string | *(empty)* | The working directory of the Broker's default Workspace, used by Sessions that are not bound to a registered Workspace. Required when `qwen.managed-agent.runtime-broker.enabled` is true. With `local-process` it must exist and is resolved to its canonical path, from which the default workspace ID is derived (for the Session Store too, even while the Broker is disabled); `kubernetes-workspace` needs an absolute normalized path, and external provisioners an absolute normalized worker-side path other than `/`. |
|
|
| `workspace-generation` | `QWEN_MANAGED_AGENT_WORKSPACE_GENERATION` | string | `1` | The generation of the Broker's default Workspace, carried in the Runtime scope of Sessions that are not bound to a registered Workspace. A non-empty string of at most 512 characters; required when `qwen.managed-agent.runtime-broker.enabled` is true. |
|
|
| `workspace-id` | `QWEN_MANAGED_AGENT_WORKSPACE_ID` | string | *(empty)* | The ID of the Broker's default Workspace, which Sessions not bound to a registered Workspace share with the Session Store. With `local-process`, empty derives the first 16 hex characters of the SHA-256 of the canonical `qwen.managed-agent.runtime-broker.workspace-cwd`, and a set value must equal that hash; other provisioners require it. With the Hosted Harness and Session Store enabled, startup refuses a value that differs from `qwen.managed-agent.session-store.workspace-id`. Keep it unchanged once Sessions exist, since unbound Sessions resolve their Store scope from it. |
|
|
| `workspace-mounts` | — | YAML list | *(empty)* | The administrator-mounted Workspace storage roots, set in a configuration file (YAML) as a list of entries with `tenant-id`, `storage-id` and `root`. Each `root` must be an existing canonical directory; roots must not overlap or alias each other, and each tenant and storage pair may appear once. Requires the `local-process` provisioner; startup refuses otherwise and with external provisioners or resident Workspaces. Every Broker sharing the database must use the same list. |
|
|
|
|
## `qwen.managed-agent.runtime-broker.retention`
|
|
|
|
Database cleanup of old terminal Runtime records (tool executions, Runtime Sessions and bindings), run in bounded batches on a dedicated scheduler.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `batch-size` | `QWEN_MANAGED_AGENT_RUNTIME_RETENTION_BATCH_SIZE` | integer | `100` | How many records one retention tick may handle: it caps the bindings scanned, the child records scanned and the total rows deleted per tick. Must be between 1 and 1000; checked at startup even while retention is off. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_RUNTIME_RETENTION_ENABLED` | boolean | `false` | Whether the server periodically deletes old terminal Runtime records (tool executions, Runtime Sessions and bindings) from the database, in bounded batches on its own scheduler. Takes effect only when `qwen.managed-agent.runtime-broker.enabled` is also true. It never stops workers or deletes Workspace files, and it keeps records that are still referenced, such as recovery records, Workspace holders and unsettled child lineage. |
|
|
| `max-age` | `QWEN_MANAGED_AGENT_RUNTIME_RETENTION_MAX_AGE` | duration | `30d` | How long a terminal Runtime record must have been inactive before retention may delete it: a binding or Runtime Session is measured from its last activity, a tool execution from when it settled or was abandoned. A suffix-less number binds as days. Must be at least `1ms`; checked at startup even while retention is off. |
|
|
| `scan-delay` | `QWEN_MANAGED_AGENT_RUNTIME_RETENTION_SCAN_DELAY` | duration | `1m` | How long the retention job waits after one tick finishes before it starts the next. A suffix-less number binds as milliseconds. Must be at least `1ms`; checked at startup even while retention is off. |
|
|
|
|
## `qwen.managed-agent.runtime-broker.ssh`
|
|
|
|
SSH Runtime nodes: hosts the server reaches over SSH, on which users may register Workspaces whose Runtime workers then run there.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `enabled` | — | boolean | — | Whether SSH Workspaces are offered: an actor listed in a node's `access` may browse that node's allowed roots and register a directory there as a Workspace; while off, those routes answer `404 ssh_runtime_disabled`. Startup refuses it without `qwen.managed-agent.harness.workspace-files-enabled` or without `qwen.managed-agent.runtime-broker.ssh.nodes`, with an external provisioner, and under the `managed-local` profile. |
|
|
| `nodes` | — | YAML list | *(empty)* | The SSH Runtime nodes, set in a configuration file (YAML) as a list. Each entry has `node-id` and `display-name`, `ssh-host` (a host alias of the server account's SSH configuration), the absolute node paths `node-executable`, `qwen-entry` and `state-directory`, `allowed-roots` (at least one absolute directory Workspaces may be registered under), `publication-port` (the node's loopback port that tool publication is forwarded to over SSH), `qwen-version` (required; must equal the version the node reports) and `access` (the `tenant-id` and `actor-id` pairs that may use the node). Startup refuses an invalid entry. With nodes set, `qwen.managed-agent.tool-publication.service-base-url` must be an `http` URL. |
|
|
|
|
## `qwen.managed-agent.session-store`
|
|
|
|
The private Managed Session Store through which the Hosted Harness reads and writes Session journals on this server's internal routes, and the writer credentials and leases that guard it.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `allow-insecure-http` | `QWEN_MANAGED_AGENT_SESSION_STORE_ALLOW_INSECURE_HTTP` | boolean | `false` | Whether a plaintext `http` `qwen.managed-agent.session-store.base-url` on a non-loopback host is accepted. Without it startup refuses such a URL, which every Harness would reject; with it the flag is passed to the Harness in each Session's Store descriptor so its client accepts the URL. |
|
|
| `base-url` | `QWEN_MANAGED_AGENT_SESSION_STORE_BASE_URL` | string | *(empty)* | The URL at which the Hosted Harness reaches this server's Session Store routes. Empty derives the loopback `http` URL of the serving listener (the internal one when `qwen.managed-agent.internal-server.port` is set) if it binds a blank, wildcard, `127.0.0.1` or `::1` address on a fixed port without TLS; otherwise set it. Startup refuses non-loopback plaintext `http` unless `qwen.managed-agent.session-store.allow-insecure-http`, and a loopback URL off the internal port. The `managed-local` profile requires a loopback `http` URL. |
|
|
| `binding-key` | `QWEN_MANAGED_AGENT_SESSION_STORE_BINDING_KEY` | string | *(empty)* | The secret HMAC key from which the control plane issues each Session's Store writer credential to the Harness; with it the Store rejects any other token, without it the Harness mints its own (first writer wins). At least 32 bytes. Required by the Harness pool, and before the internal surface leaves loopback unless `qwen.managed-agent.auth.allow-insecure-bind`; must differ from `qwen.managed-agent.auth.signing-key`. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_SESSION_STORE_ENABLED` | boolean | follows `qwen.managed-agent.harness.enabled` | Whether this server serves the private Session Store routes under `/internal/managed-session-store/v1/` and gives Hosted Sessions a Store descriptor. Startup requires it while `qwen.managed-agent.harness.enabled` is true; Workspace files and the Harness pool need it too. It exposes the internal surface, so leaving loopback then needs `qwen.managed-agent.session-store.binding-key` unless `qwen.managed-agent.auth.allow-insecure-bind` is true. Unless set, the packaged configuration follows `qwen.managed-agent.harness.enabled`. |
|
|
| `workspace-id` | `QWEN_MANAGED_AGENT_WORKSPACE_ID` | string | *(empty)* | The workspace ID that scopes the Store for Sessions not bound to a Workspace; bound Sessions use their own Workspace ID. Empty takes `qwen.managed-agent.runtime-broker.workspace-id`, otherwise the ID a `local-process` Broker derives from `qwen.managed-agent.runtime-broker.workspace-cwd`. Startup refuses it empty while the Harness uses the Store, and different from a set Runtime Broker ID. Keep it unchanged on an existing deployment. |
|
|
| `writer-lease-duration` | `QWEN_MANAGED_AGENT_SESSION_STORE_WRITER_LEASE_DURATION` | duration | `60s` | How long a Harness's writer lease on a Session's Store journal lasts before it must be renewed; also how long Session close or delete admission keeps an already-live writer. Must be between `1s` and `300s`: a value outside fails each Session's Harness create or load rather than startup. A number without a unit is read as seconds. |
|
|
|
|
## `qwen.managed-agent.tool-publication`
|
|
|
|
Durable publication of Hosted Shell tool output to object storage: the storage target, capacity limits, operation and verification deadlines, and garbage collection.
|
|
|
|
| Property | Variable | Type | Default | Description |
|
|
| --- | --- | --- | --- | --- |
|
|
| `active-captures` | — | integer | — | How many tool output captures one tenant may have open at the same time; a further reservation is refused until one finishes. Required when `qwen.managed-agent.tool-publication.enabled` is true; must be at least 1 (startup refusal). |
|
|
| `async-verification-enabled` | `QWEN_MANAGED_AGENT_TOOL_PUBLICATION_ASYNC_VERIFICATION_ENABLED` | boolean | `false` | Whether clients may ask for asynchronous verification of publication operations with the `X-Qwen-Tool-Publication-Async: 1` header, receiving HTTP 202 and polling for the outcome; otherwise every operation verifies synchronously. Turning it off stops new asynchronous admissions while already accepted operations still drain. |
|
|
| `claim-timeout` | — | duration | — | How long a server's claim on an in-progress publication operation lasts; the holder renews it every third of this period, and a retry can take the operation over only after the claim lapses. Required when tool publication is enabled; must be positive and shorter than `qwen.managed-agent.tool-publication.operation-timeout` (startup refusal). A bare number is seconds. |
|
|
| `deletion-grace` | `QWEN_MANAGED_AGENT_TOOL_PUBLICATION_DELETION_GRACE` | duration | `24h` | How long a retired Session's tool output and Session resources are kept before garbage collection may delete them. Only takes effect with `qwen.managed-agent.tool-publication.gc-enabled`; the periodic retention log sample also uses it. Must not be negative (startup refusal when tool publication is enabled). A bare number is seconds. |
|
|
| `enabled` | `QWEN_MANAGED_AGENT_TOOL_PUBLICATION_ENABLED` | boolean | `false` | Whether the server accepts tool output publication: Hosted Shell executions stream their output through the internal `/internal/managed-tool-publications` API into object storage (Aliyun OSS unless a custom store bean is registered). Startup is refused unless this group's service URL, capacities and deadlines are set, plus the OSS endpoint, region and bucket. Off a loopback address it also requires `qwen.managed-agent.session-store.binding-key`, unless `qwen.managed-agent.auth.allow-insecure-bind` is true. |
|
|
| `entry-concurrency` | — | integer | — | How many tool publication API requests this server process handles at once; a request beyond that gets HTTP 429 `managed_tool_publication_busy`. Required when tool publication is enabled; must be at least 1 (startup refusal). |
|
|
| `execution-bytes` | — | integer | — | How many bytes of output one tool execution may capture; it is also sent to the Harness as the capture limit for Shell and team-lead executions. Required when tool publication is enabled; must be between 1 byte and 2 TiB (2^41 bytes). Startup is refused if verifying that much output would exceed `qwen.managed-agent.tool-publication.max-verification-timeout`. |
|
|
| `gc-enabled` | `QWEN_MANAGED_AGENT_TOOL_PUBLICATION_GC_ENABLED` | boolean | `false` | Whether the server garbage-collects retired tool output: capture objects in object storage and the stored resources of retired Sessions, once `qwen.managed-agent.tool-publication.deletion-grace` has passed. Only read when `qwen.managed-agent.tool-publication.enabled` is true. |
|
|
| `max-verification-timeout` | — | duration | — | The longest deadline a publication verification may get. Must be positive and at most 25 minutes; startup is refused if `qwen.managed-agent.tool-publication.operation-timeout` plus the time to verify `qwen.managed-agent.tool-publication.execution-bytes` (and a fixed producer allowance) at `qwen.managed-agent.tool-publication.verification-bytes-per-second` exceeds it. Required when tool publication is enabled. A bare number is seconds. |
|
|
| `operation-timeout` | — | duration | — | How long a publication operation (upload, verification or finish) may run before its deadline; verifying stored content adds one second per `qwen.managed-agent.tool-publication.verification-bytes-per-second` bytes. Required when tool publication is enabled; must be positive and longer than `qwen.managed-agent.tool-publication.claim-timeout` (startup refusal). A bare number is seconds. |
|
|
| `oss-bucket` | — | string | *(empty)* | The Aliyun OSS bucket that stores tool output objects. Required when tool publication is enabled with the default OSS store (startup refusal); ignored when a custom `ToolPublicationObjectStore` bean is registered. |
|
|
| `oss-endpoint` | — | string | *(empty)* | The Aliyun OSS endpoint for tool output objects. Must be `https://oss-<region>.aliyuncs.com` for `qwen.managed-agent.tool-publication.oss-region`, with no path, query or user info (startup refusal otherwise). OSS credentials are secrets read from the `OSS_ACCESS_KEY_ID` and `OSS_ACCESS_KEY_SECRET` environment variables (plus `OSS_SESSION_TOKEN` for a temporary token). Required with the default OSS store; ignored when a custom store bean is registered. |
|
|
| `oss-region` | — | string | *(empty)* | The Aliyun OSS region (for example `cn-hangzhou`) used for V4 request signing; it must match the `qwen.managed-agent.tool-publication.oss-endpoint` host. Required with the default OSS store (startup refusal); ignored when a custom store bean is registered. |
|
|
| `service-base-url` | — | string | *(empty)* | The base URL that Runtimes use to reach this server's tool publication API; they resolve `/internal/managed-tool-publications` against it. Must be an absolute `http` or `https` URL without path, query or fragment; plaintext `http` to a non-loopback host is refused unless `qwen.managed-agent.auth.allow-insecure-bind` is true. Required when tool publication is enabled. With SSH Runtime nodes configured it must be an `http` URL. |
|
|
| `session-bytes` | — | integer | — | How many bytes of tool output one Session may hold reserved across its captures; each reservation counts its capture size plus a fixed overhead of 4784128 bytes. A reservation that would exceed it is refused. Required when tool publication is enabled; must be at least 1 (startup refusal). |
|
|
| `tenant-bytes` | — | integer | — | How many bytes of tool output one tenant may hold reserved across all its Sessions' captures; each reservation counts its capture size plus a fixed overhead of 4784128 bytes. A reservation that would exceed it is refused. Required when tool publication is enabled; must be at least 1 (startup refusal). |
|
|
| `verification-bytes-per-second` | — | integer | — | The verification throughput floor in bytes per second: a verification deadline is `qwen.managed-agent.tool-publication.operation-timeout` plus one second for each this many bytes being verified, and must stay within `qwen.managed-agent.tool-publication.max-verification-timeout`. Required when tool publication is enabled; must be at least 1 (startup refusal). |
|
|
| `verification-concurrency` | `QWEN_MANAGED_AGENT_TOOL_PUBLICATION_VERIFICATION_CONCURRENCY` | integer | `2` | How many background threads verify asynchronously admitted publication operations. The verifier keeps running when `qwen.managed-agent.tool-publication.async-verification-enabled` is turned off, so accepted operations drain. Must be at least 1 (startup refusal when tool publication is enabled). |
|