> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/relay/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/relay/_mcp/server.

# Adaptive Configuration

> Configure the Adaptive component, including state, telemetry, hints, ACG, and response caching.

Use this page when you want to configure the built-in Adaptive plugin component
as a whole. The component kind is `adaptive`.

Adaptive plugin configuration uses the generic NeMo Relay plugin document
shape. Canonical plugin documents and `plugins.toml` use `snake_case`.
Binding helpers can use language-native names and serialize them to canonical
keys.

For plugin file discovery, precedence, merge behavior, editor controls, and
gateway conflict rules, refer to
[Plugin Configuration Files](/configure-plugins/plugin-configuration-files).

## Component Shape

The top-level adaptive object contains:

| Field              | Purpose                                                                                                                                                         |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`          | Adaptive config schema version. Defaults to `1`.                                                                                                                |
| `agent_id`         | Fallback agent identifier used only when no Agent scope is active, such as gateway-mode requests. Scoped runtime calls use the active Agent scope name instead. |
| `state`            | Adaptive state backend.                                                                                                                                         |
| `telemetry`        | Adaptive subscriber and learner settings.                                                                                                                       |
| `adaptive_hints`   | Request hint-injection behavior.                                                                                                                                |
| `tool_parallelism` | Tool scheduling observation or scheduling behavior.                                                                                                             |
| `acg`              | Adaptive Cache Governor prompt-cache planning.                                                                                                                  |
| `response_cache`   | Opt-in cache for repeated LLM responses and classified tool results.                                                                                            |
| `policy`           | Adaptive-local handling for unknown fields and unsupported values.                                                                                              |

Dedicated pages cover [Adaptive Cache Governor (ACG)](/configure-plugins/adaptive/acg),
[Adaptive Hints](/configure-plugins/adaptive/adaptive-hints), and
[Response Cache](/configure-plugins/adaptive/response-cache). State, telemetry, tool parallelism, and
policy remain whole-plugin settings:

* Use `state.backend.kind = "in_memory"` for local experiments.
* Use Redis state when learned state must survive restarts or be shared across
  workers.
* Enable `telemetry` when adaptive learners should consume runtime events.
* Keep `tool_parallelism.mode = "observe_only"` until scheduling behavior has
  been validated.
* Keep `policy.unsupported_value = "error"` for rollout safety.

## `plugins.toml` Example

Add the following whole-plugin Adaptive configuration to `plugins.toml`:

```toml
version = 1

[[components]]
kind = "adaptive"
enabled = true

[components.config]
version = 1
agent_id = "planner"

[components.config.state.backend]
kind = "in_memory"

[components.config.telemetry]
subscriber_name = "adaptive.telemetry"
learners = ["tool_parallelism"]

[components.config.tool_parallelism]
mode = "observe_only"
priority = 100

[components.config.adaptive_hints]
priority = 100
break_chain = false
inject_header = true
inject_body_path = "nvext.agent_hints"

[components.config.acg]
provider = "passthrough"
observation_window = 100
priority = 50

[components.config.acg.stability_thresholds]
stable_threshold = 0.95
semi_stable_threshold = 0.50
min_observations_for_full_confidence = 20

[components.config.policy]
unknown_component = "warn"
unknown_field = "warn"
unsupported_value = "error"
```

This configuration activates adaptive telemetry, keeps tool parallelism
observational, injects adaptive hints, and leaves ACG in `passthrough` mode so
requests can be observed without provider-specific cache translation.

## Per-Language Plugin Configuration

The following examples configure and activate the Adaptive component through a
language binding:

`validate()` resolves the same configuration layers as `initialize()` without
loading plugin code or acquiring the activation lease. Use Python/Rust
`validate_exact()`, Node.js `validateExact()`, or Go `ValidateExact()` when only
the supplied static configuration should be checked. For complete
layering rules, refer to [Plugin Configuration Files](/configure-plugins/plugin-configuration-files).

#### Python

```python
import asyncio

import nemo_relay

adaptive_config = nemo_relay.adaptive.AdaptiveConfig(
    agent_id="planner",
    state=nemo_relay.adaptive.StateConfig(
        backend=nemo_relay.adaptive.BackendSpec.in_memory(),
    ),
    telemetry=nemo_relay.adaptive.TelemetryConfig(
        subscriber_name="adaptive.telemetry",
        learners=["tool_parallelism"],
    ),
    tool_parallelism=nemo_relay.adaptive.ToolParallelismConfig(mode="observe_only"),
    adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig(
        inject_body_path="nvext.agent_hints",
    ),
    acg=nemo_relay.adaptive.AcgConfig(provider="passthrough"),
)

plugin_config = nemo_relay.plugin.PluginConfig(
    components=[nemo_relay.adaptive.ComponentSpec(adaptive_config)]
)

report = nemo_relay.plugin.validate(plugin_config)["config"]
if any(diagnostic["level"] == "error" for diagnostic in report["diagnostics"]):
    raise RuntimeError(report["diagnostics"])

async def main():
    async with nemo_relay.plugin.activate(plugin_config):
        # Run instrumented application work here.
        pass

asyncio.run(main())
```

#### Node.js

```js
const adaptive = require("nemo-relay-node/adaptive");
const plugin = require("nemo-relay-node/plugin");

const adaptiveConfig = adaptive.defaultConfig();
adaptiveConfig.agent_id = "planner";
adaptiveConfig.state = { backend: adaptive.inMemoryBackend() };
adaptiveConfig.telemetry = adaptive.telemetryConfig({
  subscriber_name: "adaptive.telemetry",
  learners: ["tool_parallelism"],
});
adaptiveConfig.tool_parallelism = adaptive.toolParallelismConfig({ mode: "observe_only" });
adaptiveConfig.adaptive_hints = adaptive.adaptiveHintsConfig({
  inject_body_path: "nvext.agent_hints",
});
adaptiveConfig.acg = adaptive.acgConfig({ provider: "passthrough" });

const pluginConfig = plugin.defaultConfig();
pluginConfig.components = [adaptive.ComponentSpec(adaptiveConfig)];

const report = plugin.validate(pluginConfig).config;
if (report.diagnostics.some((diagnostic) => diagnostic.level === "error")) {
  throw new Error(JSON.stringify(report.diagnostics));
}

const activation = await plugin.initialize(pluginConfig);
try {
  // Run instrumented application work here.
} finally {
  await activation.close();
}
```

#### Rust

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
use nemo_relay::plugin::PluginConfig;
use nemo_relay::plugin::dynamic::{initialize, validate};
use nemo_relay_adaptive::plugin_component::{register_adaptive_component, ComponentSpec};
use nemo_relay_adaptive::{
    AdaptiveConfig,
    BackendSpec,
    StateConfig,
    TelemetryComponentConfig,
    ToolParallelismComponentConfig,
    AdaptiveHintsComponentConfig,
    AcgComponentConfig,
};

let mut adaptive = AdaptiveConfig::default();
adaptive.agent_id = Some("planner".into());
adaptive.state = Some(StateConfig {
    backend: BackendSpec::in_memory(),
});
adaptive.telemetry = Some(TelemetryComponentConfig {
    subscriber_name: Some("adaptive.telemetry".into()),
    learners: vec!["tool_parallelism".into()],
});
adaptive.tool_parallelism = Some(ToolParallelismComponentConfig::default());
adaptive.adaptive_hints = Some(AdaptiveHintsComponentConfig {
    inject_body_path: "nvext.agent_hints".into(),
    ..AdaptiveHintsComponentConfig::default()
});
adaptive.acg = Some(AcgComponentConfig {
    provider: "passthrough".into(),
    ..AcgComponentConfig::default()
});

let mut plugin_config = PluginConfig::default();
plugin_config.components.push(ComponentSpec::new(adaptive).into());

register_adaptive_component()?;
let report = validate(plugin_config.clone(), None)?;
assert!(!report.config.has_errors());

let mut activation = initialize(plugin_config, None).await?;

// Run instrumented application work here.

activation.close()?;
Ok(())
}
```

## Manual API

Use the manual runtime API when an integration needs to own adaptive lifecycle
directly instead of activating the top-level plugin component.

#### Python

```python
import asyncio

import nemo_relay

adaptive_config = nemo_relay.adaptive.AdaptiveConfig(
    agent_id="planner",
    state=nemo_relay.adaptive.StateConfig(
        backend=nemo_relay.adaptive.BackendSpec.in_memory(),
    ),
    telemetry=nemo_relay.adaptive.TelemetryConfig(
        subscriber_name="adaptive.telemetry",
        learners=["tool_parallelism"],
    ),
    tool_parallelism=nemo_relay.adaptive.ToolParallelismConfig(mode="observe_only"),
    adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig(
        inject_body_path="nvext.agent_hints",
    ),
    acg=nemo_relay.adaptive.AcgConfig(provider="passthrough"),
)

runtime = nemo_relay.adaptive.AdaptiveRuntime(adaptive_config.to_dict())
asyncio.run(runtime.register())
try:
    # Run instrumented application work here.
    runtime.wait_for_idle()
finally:
    asyncio.run(runtime.shutdown())
```

#### Node.js

The Node.js binding exposes `adaptive.AdaptiveRuntime` for manual lifecycle
ownership. Construct it from the same `adaptiveConfig`, then call `register()`,
`waitForIdle()`, and `shutdown()`.

#### Rust

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
use nemo_relay_adaptive::{
    AcgComponentConfig, AdaptiveConfig, AdaptiveHintsComponentConfig, AdaptiveRuntime,
    BackendSpec, StateConfig, TelemetryComponentConfig, ToolParallelismComponentConfig,
};

let mut adaptive = AdaptiveConfig::default();
adaptive.agent_id = Some("planner".into());
adaptive.state = Some(StateConfig {
    backend: BackendSpec::in_memory(),
});
adaptive.telemetry = Some(TelemetryComponentConfig {
    subscriber_name: Some("adaptive.telemetry".into()),
    learners: vec!["tool_parallelism".into()],
});
adaptive.tool_parallelism = Some(ToolParallelismComponentConfig::default());
adaptive.adaptive_hints = Some(AdaptiveHintsComponentConfig {
    inject_body_path: "nvext.agent_hints".into(),
    ..AdaptiveHintsComponentConfig::default()
});
adaptive.acg = Some(AcgComponentConfig {
    provider: "passthrough".into(),
    ..AcgComponentConfig::default()
});

let mut runtime = AdaptiveRuntime::new(adaptive).await?;
runtime.register().await?;

// Run instrumented application work here.

runtime.wait_for_idle();
runtime.shutdown().await?;
Ok(())
}
```

## Validation and Teardown

Validate plugin configuration before initialization. Disabled components are
excluded from the effective host; validate their component-local configuration
before enabling them when preparing a rollout.

Common validation failures include:

* Unknown adaptive fields when policy treats unknown fields as errors.
* Unsupported backend kinds, tool-parallelism modes, or ACG providers.
* Unsupported schema versions.
* Backend-specific fields that do not match the selected backend.

Close the activation during shutdown or test cleanup. Closing the activation
deregisters the adaptive subscribers and intercepts owned by the plugin runtime.

## Rollout Guidance

Start by enabling state and telemetry in a development environment. Run
representative instrumented workflows, inspect emitted events and adaptive
reports, and then enable active behavior one area at a time. Keep rollback as a
configuration change.