Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,448 changes: 8,791 additions & 5,657 deletions ATTRIBUTIONS-Rust.md

Large diffs are not rendered by default.

265 changes: 264 additions & 1 deletion Cargo.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ nemo-relay plugins edit --project
```

The editor creates or updates the nearest project plugin file at
`.nemo-relay/plugins.toml`. In the menu:
`.nemo-relay/plugins.toml`. In the top-level menu, select **Observability**,
then configure these sections:

1. Enable the `Observability` component.
1. Toggle the Observability component on.
2. Open `ATOF`, toggle the section `[on]`

Optionally set:
Expand All @@ -84,7 +85,7 @@ The editor creates or updates the nearest project plugin file at
Optionally set:
- `output_directory` to `.nemo-relay/atif`
- `filename_template` to `trajectory-{session_id}.json`
4. Press `p` to preview the generated TOML.
4. Return to the top-level menu and press `p` to preview the generated TOML.
5. Press `s` to save.

> [!NOTE]
Expand Down
1 change: 1 addition & 0 deletions about.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ accepted = [
"BSL-1.0",
"ISC",
"MIT",
"MIT-0",
"MPL-2.0",
"Unicode-3.0",
"Zlib",
Expand Down
4 changes: 3 additions & 1 deletion crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ console = "0.16"
futures-util = "0.3"
http = "1"
http-body-util = "0.1"
dialoguer = { version = "0.11", default-features = false }
dialoguer = { version = "0.11", default-features = false, features = ["password"] }
jsonschema = { version = "0.46.6", default-features = false }
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-native-roots-no-provider", "stream"] }
regex = "1"
ring = "0.17"
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
serde = { version = "1", features = ["derive"] }
Expand Down
5 changes: 5 additions & 0 deletions crates/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ plugin config with:
nemo-relay plugins edit
```

The top-level editor menu contains one entry per supported built-in, followed by
the dynamic plugin references in the selected physical `plugins.toml`. Dynamic
plugins with a manifest-declared JSON Schema provide structured field controls.
Other dynamic plugins use a raw JSON object editor.

The canonical plugin file is `plugins.toml`; user config lives at
`~/.config/nemo-relay/plugins.toml` or
`$XDG_CONFIG_HOME/nemo-relay/plugins.toml`. Project config lives at
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ pub(crate) struct PluginJsonContext<'a> {
/// Plugin configuration subcommands.
#[derive(Debug, Clone, Subcommand)]
pub(crate) enum PluginsSubcommand {
/// Interactively create or edit built-in plugin configuration in `plugins.toml`.
/// Interactively create or edit built-in and dynamic plugin configuration.
Edit(PluginsEditCommand),
/// Register a manifest-backed dynamic plugin in `plugins.toml`.
Add(PluginsAddCommand),
Expand Down
55 changes: 31 additions & 24 deletions crates/cli/src/model_pricing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ use crate::config::{
PricingValidateCommand, ServerArgs, resolve_server_config,
};
use crate::error::CliError;
use crate::plugins::config_io::{
TargetScope, read_plugin_config, target_path, validate_config, write_plugin_config,
};
use crate::plugins::config_io::{PluginConfigDocument, TargetScope, target_path, validate_config};

const PRICING_PLUGIN_KIND: &str = "pricing";

Expand All @@ -37,13 +35,13 @@ pub(crate) fn validate(command: PricingValidateCommand) -> Result<(), CliError>
pub(crate) fn init(command: PricingInitCommand) -> Result<(), CliError> {
let scope = target_pricing_scope(&command.scope)?;
let path = target_path(scope)?;
let mut plugin_config = read_plugin_config(&path)?;
let index = ensure_pricing_component(&mut plugin_config)?;
let pricing_config = pricing_config_from_component(&plugin_config.components[index])?;
store_pricing_config(&mut plugin_config.components[index], &pricing_config)?;
plugin_config.components[index].enabled = true;
validate_config(&plugin_config)?;
write_plugin_config(&path, &plugin_config)?;
update_plugin_config_document(&path, |plugin_config| {
let index = ensure_pricing_component(plugin_config)?;
let pricing_config = pricing_config_from_component(&plugin_config.components[index])?;
store_pricing_config(&mut plugin_config.components[index], &pricing_config)?;
plugin_config.components[index].enabled = true;
Ok(())
})?;
println!("Initialized model pricing config: {}", path.display());
Ok(())
}
Expand All @@ -58,23 +56,22 @@ pub(crate) fn add_source(command: PricingAddSourceCommand) -> Result<(), CliErro
read_pricing_catalog(&source_path)?;
let scope = target_pricing_scope(&command.scope)?;
let path = target_path(scope)?;
let mut plugin_config = read_plugin_config(&path)?;
let index = ensure_pricing_component(&mut plugin_config)?;
let mut pricing_config = pricing_config_from_component(&plugin_config.components[index])?;
let source = PricingSourceConfig::File { path: source_path };

if !pricing_config.sources.contains(&source) {
if command.append {
pricing_config.sources.push(source);
} else {
pricing_config.sources.insert(0, source);
update_plugin_config_document(&path, |plugin_config| {
let index = ensure_pricing_component(plugin_config)?;
let mut pricing_config = pricing_config_from_component(&plugin_config.components[index])?;
if !pricing_config.sources.contains(&source) {
if command.append {
pricing_config.sources.push(source);
} else {
pricing_config.sources.insert(0, source);
}
}
}

store_pricing_config(&mut plugin_config.components[index], &pricing_config)?;
plugin_config.components[index].enabled = true;
validate_config(&plugin_config)?;
write_plugin_config(&path, &plugin_config)?;
store_pricing_config(&mut plugin_config.components[index], &pricing_config)?;
plugin_config.components[index].enabled = true;
Ok(())
})?;
println!(
"Added model pricing source: {} -> {}",
command.path.display(),
Expand All @@ -83,6 +80,16 @@ pub(crate) fn add_source(command: PricingAddSourceCommand) -> Result<(), CliErro
Ok(())
}

fn update_plugin_config_document(
path: &Path,
update: impl FnOnce(&mut PluginConfig) -> Result<(), CliError>,
) -> Result<(), CliError> {
let mut document = PluginConfigDocument::read(path)?;
update(document.config_mut())?;
validate_config(document.config())?;
document.write()
}

pub(crate) fn resolve(command: PricingResolveCommand) -> Result<(), CliError> {
let sources = pricing_catalog_sources_from_current_config()?;
if sources.is_empty() {
Expand Down
Loading
Loading