Skip to content
Merged
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,19 @@ Remove-Item -Recurse -Force (Join-Path $userProfile ".braintrust\auth") -ErrorAc

## `bt observability template`

Copy custom facets, their Topics automation settings, and Loop automations between projects:

```bash
bt observability template pull --output observability-template.json --project test-source-project
bt observability template push observability-template.json --project test-destination-project
```

Schema v2 adds `topics_automations`, with each referenced automation's name, description, and API-returned config. Scope, automation-level BTQL filters, sampling, model, status, and timing travel with the facet. Project-specific `facet_functions` and `topic_map_functions` wiring is rebuilt in the destination. Version 1 templates remain readable and use destination/default Topics settings.

New automations use the bundled settings. Existing automations with matching settings and descriptions retain them. Differences require `--force`, which replaces settings in full while preserving destination facet/map wiring; destination-only settings are dropped. `--topics-automation <NAME_OR_ID>` uses that existing automation's settings instead of the template's. Existing resource replacement rules still apply to facet and preprocessor definitions.

Settings scoped to a specific experiment cannot be exported because its ID is project-specific. Timing validation and normalization remain with the server; settings returned by the API may differ from the submitted values. Topic map definitions and generated state are not exported. Topics update when the pipeline runs again.

Push with `--force` replaces an imported facet's topic map binding in the selected automation. It reuses the map with the generated template slug, or creates that map if needed, and detaches superseded maps from that automation. Other automations keep their facet and map bindings. Detached map functions remain in the project and are listed in human and JSON push output. Existing generated state updates when the Topics pipeline runs again.

## `bt custom-views`
Expand Down
3 changes: 2 additions & 1 deletion src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2734,11 +2734,12 @@ fn build_js_plan(
}

fn build_vite_node_fallback_command(runner: &Path, files: &[String]) -> Result<Command> {
let runner = js_runner_path_for_kind(runner, RunnerKind::ViteNode);
if let Some(path) = find_node_module_bin_for_files("vite-node", files)
.or_else(|| js_runner::find_binary_in_path(&["vite-node"]))
{
let mut command = Command::new(path);
command.arg(runner).args(files);
command.arg(&runner).args(files);
return Ok(command);
}

Expand Down
6 changes: 3 additions & 3 deletions src/observability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub(crate) struct ObservabilityArgs {

#[derive(Debug, Clone, Subcommand)]
enum ObservabilityCommand {
/// Pull and push facets and Loop automations as a portable template
/// Pull and push facets, Topics settings, and Loop automations as a portable template
Template(TemplateArgs),
}

Expand All @@ -47,9 +47,9 @@ struct TemplateArgs {

#[derive(Debug, Clone, Subcommand)]
enum TemplateCommand {
/// Pull facets and Loop automations into a portable template
/// Pull facets, Topics settings, and Loop automations into a portable template
Pull(PullArgs),
/// Push facets and Loop automations from a portable template
/// Push facets, Topics settings, and Loop automations from a portable template
Push(PushArgs),
}

Expand Down
7 changes: 5 additions & 2 deletions src/observability/pull.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::{

use super::{
template::{
deduplicate_preprocessors, from_remote, ActiveObservabilityTemplate, AutomationTemplate,
FacetTemplate,
deduplicate_preprocessors, from_remote, retain_topics_settings, validate,
validate_topics_scope, ActiveObservabilityTemplate, AutomationTemplate, FacetTemplate,
},
PullArgs,
};
Expand All @@ -41,6 +41,9 @@ pub(crate) async fn run(base: BaseArgs, args: PullArgs) -> Result<()> {
(template.facets, template.automations) =
filter_active_resources(template.facets, template.automations);
}
retain_topics_settings(&mut template, &functions, &automations)?;
validate(&template)?;
validate_topics_scope(&template)?;
// Selection happens first so a selected facet never loses its required definition.
deduplicate_preprocessors(&mut template.facets);

Expand Down
Loading
Loading